13#ifndef LLVM_CLANG_AST_INTERP_INTERP_H
14#define LLVM_CLANG_AST_INTERP_INTERP_H
35#include "llvm/ADT/APFloat.h"
36#include "llvm/ADT/APSInt.h"
37#include "llvm/ADT/ScopeExit.h"
38#include "llvm/Support/Compiler.h"
45#if !defined(__aarch64__) && !defined(__i386__) && \
46 !__has_feature(address_sanitizer) && \
47 __has_cpp_attribute(clang::preserve_none)
48#define PRESERVE_NONE [[clang::preserve_none]]
56using APSInt = llvm::APSInt;
95 bool WillBeActivated =
false);
121 uint32_t VarArgSize);
123 uint32_t VarArgSize);
125 uint32_t VarArgSize);
133 bool TargetIsUCharOrByte);
149 bool IsReferenceCast);
166 const APSInt *
Value =
nullptr,
170template <ShiftDir Dir,
typename LT,
typename RT>
173 if (RHS.isNegative()) {
188 if (LHS.isSigned() && !S.
getLangOpts().CPlusPlus20) {
191 if (LHS.isNegative()) {
196 }
else if (LHS.toUnsigned().countLeadingZeros() <
197 static_cast<unsigned>(RHS)) {
215 if (!LHS.isNumber() || !RHS.isNumber())
221 if constexpr (std::is_same_v<T, Floating>) {
222 S.
CCEDiag(Op, diag::note_expr_divide_by_zero)
223 << Op->getRHS()->getSourceRange();
227 S.
FFDiag(Op, diag::note_expr_divide_by_zero)
228 << Op->getRHS()->getSourceRange();
232 if constexpr (!std::is_same_v<T, FixedPoint>) {
233 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
234 APSInt LHSInt = LHS.toAPSInt();
236 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
239 S.
CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->
getType();
249 APFloat::opStatus Status,
FPOptions FPO);
270template <PrimType Name, class T = typename PrimConv<Name>::T>
323 template <typename U>
class OpAP>
328 assert(LHS.isNumber() && RHS.isNumber());
344 if constexpr (std::is_same_v<T, FixedPoint>)
360 .toString(Trunc, 10,
Result.isSigned(),
false,
374template <
typename T,
template <
typename U>
class Op>
376 assert(!LHS.isNumber() || !RHS.isNumber());
380 typename T::ReprT Offset;
382 if (LHS.isNumber()) {
386 Number =
static_cast<typename T::ReprT
>(LHS);
388 Offset = RHS.getOffset();
389 Kind = RHS.getKind();
391 assert(RHS.isNumber());
395 Number =
static_cast<typename T::ReprT
>(RHS);
397 Offset = LHS.getOffset();
398 Kind = LHS.getKind();
405template <PrimType Name, class T = typename PrimConv<Name>::T>
407 const T &RHS = S.
Stk.
pop<T>();
408 const T &LHS = S.
Stk.
pop<T>();
409 const unsigned Bits = RHS.bitWidth() + 1;
412 if (LHS.isNumber() != RHS.isNumber())
414 else if (LHS.isNumber() && RHS.isNumber())
434template <PrimType Name, class T = typename PrimConv<Name>::T>
436 const T &RHS = S.
Stk.
pop<T>();
437 const T &LHS = S.
Stk.
pop<T>();
438 const unsigned Bits = RHS.bitWidth() + 1;
447 ?
reinterpret_cast<const Expr *
>(LHS.getPtr())
450 ?
reinterpret_cast<const Expr *
>(RHS.getPtr())
452 if (!isa_and_nonnull<AddrLabelExpr>(A) ||
453 !isa_and_nonnull<AddrLabelExpr>(B))
458 if (LHSAddrExpr->getLabel()->getDeclContext() !=
459 RHSAddrExpr->getLabel()->getDeclContext())
462 S.
Stk.
push<T>(LHSAddrExpr, RHSAddrExpr);
466 if (!LHS.isNumber() && RHS.isNumber())
468 else if (LHS.isNumber() && RHS.isNumber())
488template <PrimType Name, class T = typename PrimConv<Name>::T>
490 const T &RHS = S.
Stk.
pop<T>();
491 const T &LHS = S.
Stk.
pop<T>();
492 const unsigned Bits = RHS.bitWidth() * 2;
495 if (!LHS.isNumber() || !RHS.isNumber())
515template <PrimType Name, class T = typename PrimConv<Name>::T>
521 if constexpr (std::is_same_v<T, Floating>) {
527 APFloat ResR(A.getSemantics());
528 APFloat ResI(A.getSemantics());
539 Result.initializeAllElements();
542 const T &LHSR = LHS.elem<T>(0);
543 const T &LHSI = LHS.elem<T>(1);
544 const T &RHSR = RHS.
elem<T>(0);
545 const T &RHSI = RHS.
elem<T>(1);
546 unsigned Bits = LHSR.bitWidth();
549 if (!LHSR.isNumber() || !LHSI.isNumber() || !RHSR.isNumber() ||
557 if (T::mul(LHSR, RHSR,
Bits, &A))
563 if (T::mul(LHSI, RHSI,
Bits, &B))
572 if (T::mul(LHSR, RHSI,
Bits, &A))
574 if (T::mul(LHSI, RHSR,
Bits, &B))
582 Result.initializeAllElements();
588template <PrimType Name, class T = typename PrimConv<Name>::T>
594 if constexpr (std::is_same_v<T, Floating>) {
600 APFloat ResR(A.getSemantics());
601 APFloat ResI(A.getSemantics());
613 Result.initializeAllElements();
616 const T &LHSR = LHS.elem<T>(0);
617 const T &LHSI = LHS.elem<T>(1);
618 const T &RHSR = RHS.
elem<T>(0);
619 const T &RHSI = RHS.
elem<T>(1);
620 unsigned Bits = LHSR.bitWidth();
622 if (RHSR.isZero() && RHSI.isZero()) {
624 S.
FFDiag(E, diag::note_expr_divide_by_zero);
635 if (T::mul(RHSR, RHSR,
Bits, &A) || T::mul(RHSI, RHSI,
Bits, &B)) {
642 if (T::add(A, B,
Bits, &Den))
647 S.
FFDiag(E, diag::note_expr_divide_by_zero);
652 T &ResultR =
Result.elem<T>(0);
653 T &ResultI =
Result.elem<T>(1);
658 if (T::mul(LHSR, RHSR,
Bits, &A) || T::mul(LHSI, RHSI,
Bits, &B))
660 if (T::add(A, B,
Bits, &ResultR))
662 if (T::div(ResultR, Den,
Bits, &ResultR))
666 if (T::mul(LHSI, RHSR,
Bits, &A) || T::mul(LHSR, RHSI,
Bits, &B))
668 if (T::sub(A, B,
Bits, &ResultI))
670 if (T::div(ResultI, Den,
Bits, &ResultI))
672 Result.initializeAllElements();
681template <PrimType Name, class T = typename PrimConv<Name>::T>
683 const T &RHS = S.
Stk.
pop<T>();
684 const T &LHS = S.
Stk.
pop<T>();
685 unsigned Bits = RHS.bitWidth();
688 if (!LHS.isNumber() || !RHS.isNumber())
706template <PrimType Name, class T = typename PrimConv<Name>::T>
708 const T &RHS = S.
Stk.
pop<T>();
709 const T &LHS = S.
Stk.
pop<T>();
710 unsigned Bits = RHS.bitWidth();
713 if (!LHS.isNumber() || !RHS.isNumber())
731template <PrimType Name, class T = typename PrimConv<Name>::T>
733 const T &RHS = S.
Stk.
pop<T>();
734 const T &LHS = S.
Stk.
pop<T>();
735 unsigned Bits = RHS.bitWidth();
738 if (!LHS.isNumber() || !RHS.isNumber())
756template <PrimType Name, class T = typename PrimConv<Name>::T>
758 const T &RHS = S.
Stk.
pop<T>();
759 const T &LHS = S.
Stk.
pop<T>();
760 const unsigned Bits = RHS.bitWidth() * 2;
779template <PrimType Name, class T = typename PrimConv<Name>::T>
781 const T &RHS = S.
Stk.
pop<T>();
782 const T &LHS = S.
Stk.
pop<T>();
783 const unsigned Bits = RHS.bitWidth() * 2;
797 if constexpr (std::is_same_v<T, FixedPoint>) {
836template <PrimType Name, class T = typename PrimConv<Name>::T>
840 if constexpr (std::is_same_v<T, Floating>) {
859 "don't expect other types to fail at constexpr negation");
870 NegatedValue.trunc(
Result.bitWidth())
871 .toString(Trunc, 10,
Result.isSigned(),
false,
891template <
typename T, IncDecOp Op, PushVal DoPush>
901 if constexpr (std::is_same_v<T, Boolean>) {
910 if (!
Value.isNumber())
922 if (!T::increment(
Value, &
Result) || !CanOverflow) {
930 if (!T::decrement(
Value, &
Result) || !CanOverflow) {
959 APResult.trunc(
Result.bitWidth())
960 .toString(Trunc, 10,
Result.isSigned(),
false,
973template <PrimType Name, class T = typename PrimConv<Name>::T>
985template <PrimType Name, class T = typename PrimConv<Name>::T>
1001template <PrimType Name, class T = typename PrimConv<Name>::T>
1012template <PrimType Name, class T = typename PrimConv<Name>::T>
1014 uint32_t BitWidth) {
1025template <PrimType Name, class T = typename PrimConv<Name>::T>
1036template <PrimType Name, class T = typename PrimConv<Name>::T>
1038 uint32_t BitWidth) {
1053template <PrimType Name, class T = typename PrimConv<Name>::T>
1064template <PrimType Name, class T = typename PrimConv<Name>::T>
1066 uint32_t BitWidth) {
1080template <PrimType Name, class T = typename PrimConv<Name>::T>
1091template <PrimType Name, class T = typename PrimConv<Name>::T>
1093 uint32_t BitWidth) {
1104template <PrimType Name, class T = typename PrimConv<Name>::T>
1114template <PrimType Name, class T = typename PrimConv<Name>::T>
1116 uint32_t BitWidth) {
1126template <IncDecOp Op, PushVal DoPush>
1136 llvm::APFloat::opStatus Status;
1189template <PrimType Name, class T = typename PrimConv<Name>::T>
1191 const T &Val = S.
Stk.
pop<T>();
1197 if (!T::comp(Val, &
Result)) {
1210template <
typename T>
1212 assert((!std::is_same_v<T, MemberPointer>) &&
1213 "Non-equality comparisons on member pointer types should already be "
1214 "rejected in Sema.");
1216 const T &RHS = S.
Stk.
pop<T>();
1217 const T &LHS = S.
Stk.
pop<T>();
1220 if (!LHS.isNumber() || !RHS.isNumber())
1224 S.
Stk.
push<BoolT>(BoolT::from(
Fn(LHS.compare(RHS))));
1228template <
typename T>
1243 S.
FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1256 S.
FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1264 if (std::optional<std::pair<PtrView, PtrView>> Split =
1266 const FieldDecl *LF = Split->first.getField();
1267 const FieldDecl *RF = Split->second.getField();
1270 diag::note_constexpr_pointer_comparison_base_classes);
1273 diag::note_constexpr_pointer_comparison_base_field)
1274 << Split->first.getRecord()->getDecl() << RF->
getParent() << RF;
1277 diag::note_constexpr_pointer_comparison_base_field)
1278 << Split->second.getRecord()->getDecl() << LF->
getParent() << LF;
1282 diag::note_constexpr_pointer_comparison_differing_access)
1297 return (
Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
1298 Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
1299 Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||
1300 Builtin == Builtin::BI__builtin_function_start);
1312 if (LHS.isZero() && RHS.
isZero()) {
1318 for (
const auto &P : {LHS, RHS}) {
1323 S.
FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
1330 if (RHS.
isZero() || LHS.isZero()) {
1335 assert(!LHS.isZero());
1354 S.
FFDiag(Loc, diag::note_constexpr_literal_comparison)
1362 std::optional<size_t> A = LHS.computeOffsetForComparison(S.
getASTContext());
1375 S.
FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
1379 if (RHS.
isOnePastEnd() && !LHS.isOnePastEnd() && LHS.isBlockPointer() &&
1380 LHS.getOffset() == 0) {
1382 S.
FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
1388 for (
const auto &P : {LHS, RHS}) {
1391 if (P.pointsToLiteral()) {
1392 const Expr *E = P.getDeclDesc()->asExpr();
1395 S.
FFDiag(Loc, diag::note_constexpr_literal_comparison);
1398 if (
const auto *CE = dyn_cast<CallExpr>(E);
1401 S.
FFDiag(Loc, diag::note_constexpr_opaque_call_comparison)
1405 }
else if (P.isIntegralPointer()) {
1407 S.
FFDiag(Loc, diag::note_constexpr_pointer_constant_comparison)
1416 S.
FFDiag(Loc, diag::note_constexpr_pointer_comparison_zero_sized)
1425 diag::note_constexpr_pointer_comparison_unspecified)
1443 for (
const auto &MP : {LHS, RHS}) {
1446 S.
FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison)
1447 << MP.getMemberFunction();
1455 if (LHS.
isZero() && RHS.isZero()) {
1459 if (LHS.
isZero() || RHS.isZero()) {
1465 for (
const auto &MP : {LHS, RHS}) {
1469 S.
CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
1477template <PrimType Name, class T = typename PrimConv<Name>::T>
1484template <PrimType Name, class T = typename PrimConv<Name>::T>
1486 const T &RHS = S.
Stk.
pop<T>();
1487 const T &LHS = S.
Stk.
pop<T>();
1491 if constexpr (std::is_same_v<T, Pointer>) {
1494 S.
FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1502 const auto *CmpValueInfo =
1504 assert(CmpValueInfo);
1505 assert(CmpValueInfo->hasValidIntValue());
1509template <PrimType Name, class T = typename PrimConv<Name>::T>
1516template <PrimType Name, class T = typename PrimConv<Name>::T>
1523template <PrimType Name, class T = typename PrimConv<Name>::T>
1531template <PrimType Name, class T = typename PrimConv<Name>::T>
1538template <PrimType Name, class T = typename PrimConv<Name>::T>
1550template <PrimType Name, class T = typename PrimConv<Name>::T>
1556template <PrimType Name, class T = typename PrimConv<Name>::T>
1567 const auto &Top = S.
Stk.
pop<TopT>();
1568 const auto &Bottom = S.
Stk.
pop<BottomT>();
1580template <PrimType Name, class T = typename PrimConv<Name>::T>
1584 Result.copy(Arg.toAPSInt());
1589 if constexpr (std::is_same_v<T, uint16_t>) {
1591 }
else if constexpr (std::is_same_v<T, int16_t>) {
1593 }
else if constexpr (std::is_same_v<T, uint32_t>) {
1595 }
else if constexpr (std::is_same_v<T, int32_t>) {
1597 }
else if constexpr (std::is_same_v<T, uint64_t>) {
1599 }
else if constexpr (std::is_same_v<T, int64_t>) {
1620template <PrimType Name, class T = typename PrimConv<Name>::T>
1630bool PseudoDtor(InterpState &S, CodePtr OpPC);
1638template <PrimType Name, class T = typename PrimConv<Name>::T>
1644template <PrimType Name, class T = typename PrimConv<Name>::T>
1653template <PrimType Name, class T = typename PrimConv<Name>::T>
1661template <PrimType Name, class T = typename PrimConv<Name>::T>
1678 S.
Stk.
push<T>(Field.deref<T>());
1684template <PrimType Name, class T = typename PrimConv<Name>::T>
1701 S.
Stk.
push<T>(Field.deref<T>());
1705template <PrimType Name, class T = typename PrimConv<Name>::T>
1717 Field.deref<T>() =
Value;
1721template <PrimType Name, class T = typename PrimConv<Name>::T>
1731 S.
Stk.
push<T>(Field.deref<T>());
1735template <PrimType Name, class T = typename PrimConv<Name>::T>
1746 Field.deref<T>() =
Value;
1750template <PrimType Name, class T = typename PrimConv<Name>::T>
1762template <PrimType Name, class T = typename PrimConv<Name>::T>
1773template <PrimType Name, class T = typename PrimConv<Name>::T>
1779template <PrimType Name, class T = typename PrimConv<Name>::T>
1785 if constexpr (std::is_same_v<T, Floating>) {
1787 if (!Val.singleWord()) {
1788 uint64_t *NewMemory =
new (S.
P) uint64_t[Val.numWords()];
1789 Val.take(NewMemory);
1792 }
else if constexpr (std::is_same_v<T, MemberPointer>) {
1796 for (
unsigned I = 0; I != PathLength; ++I) {
1797 NewPath[I] = Val.getPathEntry(I);
1799 Val.takePath(NewPath);
1801 auto &Val = P.
deref<T>();
1802 if (!Val.singleWord()) {
1803 uint64_t *NewMemory =
new (S.
P) uint64_t[Val.numWords()];
1804 Val.take(NewMemory);
1815template <PrimType Name, class T = typename PrimConv<Name>::T>
1847template <PrimType Name, class T = typename PrimConv<Name>::T>
1854 if (!
This.isDereferencable())
1858 assert(Field.canBeInitialized());
1859 Field.deref<T>() = S.
Stk.
pop<T>();
1864template <PrimType Name, class T = typename PrimConv<Name>::T>
1871 if (!
This.isDereferencable())
1875 assert(Field.canBeInitialized());
1876 Field.deref<T>() = S.
Stk.
pop<T>();
1882template <PrimType Name, class T = typename PrimConv<Name>::T>
1884 uint32_t FieldBitWidth) {
1890 if (!
This.isDereferencable())
1894 assert(Field.canBeInitialized());
1898 if (!
Value.isNumber())
1902 Field.deref<T>() =
Value.truncate(FieldBitWidth);
1907template <PrimType Name, class T = typename PrimConv<Name>::T>
1909 uint32_t FieldOffset, uint32_t FieldBitWidth) {
1915 if (!
This.isDereferencable())
1919 assert(Field.canBeInitialized());
1923 if (!
Value.isNumber())
1927 Field.deref<T>() =
Value.truncate(FieldBitWidth);
1936template <PrimType Name, class T = typename PrimConv<Name>::T>
1940 if (!Ptr.isDereferencable())
1954template <PrimType Name, class T = typename PrimConv<Name>::T>
1958 if (!Ptr.isDereferencable())
1972template <PrimType Name, class T = typename PrimConv<Name>::T>
1974 uint32_t FieldBitWidth) {
1977 if (!Ptr.isDereferencable())
1981 if (!
Value.isNumber())
1991 unsigned BitWidth = std::min(FieldBitWidth,
Value.bitWidth());
1994 if constexpr (T::isSigned())
1996 Value.toAPSInt().trunc(BitWidth).sextOrTrunc(
Value.bitWidth()));
1999 Value.toAPSInt().trunc(BitWidth).zextOrTrunc(
Value.bitWidth()));
2001 Field.deref<T>() =
Result;
2003 Field.deref<T>() =
Value.truncate(FieldBitWidth);
2009template <PrimType Name, class T = typename PrimConv<Name>::T>
2011 uint32_t FieldBitWidth) {
2014 if (!Ptr.isDereferencable())
2018 if (!
Value.isNumber())
2028 unsigned BitWidth = std::min(FieldBitWidth,
Value.bitWidth());
2031 if constexpr (T::isSigned())
2033 Value.toAPSInt().trunc(BitWidth).sextOrTrunc(
Value.bitWidth()));
2036 Value.toAPSInt().trunc(BitWidth).zextOrTrunc(
Value.bitWidth()));
2038 Field.deref<T>() =
Result;
2040 Field.deref<T>() =
Value.truncate(FieldBitWidth);
2108bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t
Off,
bool NullOK);
2111 const Type *TargetType);
2176 diag::note_constexpr_dereferencing_null);
2189 const Record::Base *VirtBase =
Base.getRecord()->getVirtualBase(
Decl);
2220template <PrimType Name, class T = typename PrimConv<Name>::T>
2233template <PrimType Name, class T = typename PrimConv<Name>::T>
2246template <PrimType Name, class T = typename PrimConv<Name>::T>
2252 if (!Ptr.canDeref(Name))
2254 if (Ptr.canBeInitialized())
2256 Ptr.deref<T>() =
Value;
2260template <PrimType Name, class T = typename PrimConv<Name>::T>
2266 if (!Ptr.canDeref(Name))
2268 if (Ptr.canBeInitialized())
2270 Ptr.deref<T>() =
Value;
2293template <PrimType Name, class T = typename PrimConv<Name>::T>
2300 if (Ptr.canBeInitialized()) {
2308template <PrimType Name, class T = typename PrimConv<Name>::T>
2315 if (Ptr.canBeInitialized()) {
2323template <PrimType Name, class T = typename PrimConv<Name>::T>
2330 if (Ptr.canBeInitialized())
2332 if (
const auto *FD = Ptr.getField())
2333 Ptr.deref<T>() =
Value.truncate(FD->getBitWidthValue());
2335 Ptr.deref<T>() =
Value;
2339template <PrimType Name, class T = typename PrimConv<Name>::T>
2345 if (Ptr.canBeInitialized())
2347 if (
const auto *FD = Ptr.getField())
2348 Ptr.deref<T>() =
Value.truncate(FD->getBitWidthValue());
2350 Ptr.deref<T>() =
Value;
2354template <PrimType Name, class T = typename PrimConv<Name>::T>
2361 if (Ptr.canBeInitialized()) {
2365 if (
const auto *FD = Ptr.getField())
2366 Ptr.
deref<T>() =
Value.truncate(FD->getBitWidthValue());
2368 Ptr.deref<T>() =
Value;
2372template <PrimType Name, class T = typename PrimConv<Name>::T>
2379 if (Ptr.canBeInitialized()) {
2383 if (
const auto *FD = Ptr.getField())
2384 Ptr.
deref<T>() =
Value.truncate(FD->getBitWidthValue());
2386 Ptr.deref<T>() =
Value;
2390template <PrimType Name, class T = typename PrimConv<Name>::T>
2397 new (&Ptr.deref<T>()) T(
Value);
2401template <PrimType Name, class T = typename PrimConv<Name>::T>
2408 new (&Ptr.deref<T>()) T(
Value);
2415template <PrimType Name, class T = typename PrimConv<Name>::T>
2420 if (Ptr.isConstexprUnknown())
2429 if (Idx == 0 && !Desc->
isArray()) {
2431 new (&Ptr.deref<T>()) T(
Value);
2441 S.
FFDiag(Loc, diag::note_constexpr_access_past_end)
2446 Ptr.initializeElement(Idx);
2447 new (&Ptr.elem<T>(Idx)) T(
Value);
2452template <PrimType Name, class T = typename PrimConv<Name>::T>
2457 if (Ptr.isConstexprUnknown())
2466 if (Idx == 0 && !Desc->
isArray()) {
2468 new (&Ptr.deref<T>()) T(
Value);
2478 S.
FFDiag(Loc, diag::note_constexpr_access_past_end)
2483 Ptr.initializeElement(Idx);
2484 new (&Ptr.elem<T>(Idx)) T(
Value);
2497 return DoMemcpy(S, OpPC, Src, Dest);
2511 if (std::optional<Pointer> Ptr = MP.toPointer(S.
Ctx)) {
2522template <
class T, ArithOp Op>
2524 const T &Offset,
const Pointer &Ptr,
2525 bool IsPointerArith =
false) {
2527 if (Offset.isZero())
2534 return std::nullopt;
2539 return std::nullopt;
2549 uint64_t O =
static_cast<uint64_t
>(Offset) * ElemSize;
2555 uint64_t O =
static_cast<uint64_t
>(Offset);
2567 return std::nullopt;
2572 uint64_t MaxIndex =
static_cast<uint64_t
>(Ptr.
getNumElems());
2581 auto DiagInvalidOffset = [&]() ->
void {
2582 const unsigned Bits = Offset.bitWidth();
2583 APSInt APOffset(Offset.toAPSInt().extend(
Bits + 2),
false);
2587 (Op ==
ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
2589 << NewIndex <<
static_cast<int>(!Ptr.
inArray()) << MaxIndex;
2594 uint64_t IOffset =
static_cast<uint64_t
>(Offset);
2595 uint64_t MaxOffset = MaxIndex - Index;
2599 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
2600 DiagInvalidOffset();
2603 if (Offset.isPositive() && IOffset > MaxOffset)
2604 DiagInvalidOffset();
2607 if (Offset.isPositive() && Index < IOffset)
2608 DiagInvalidOffset();
2611 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
2612 DiagInvalidOffset();
2617 return std::nullopt;
2620 int64_t WideIndex =
static_cast<int64_t
>(Index);
2621 int64_t WideOffset =
static_cast<int64_t
>(Offset);
2624 Result = WideIndex + WideOffset;
2626 Result = WideIndex - WideOffset;
2640template <PrimType Name, class T = typename PrimConv<Name>::T>
2642 const T &Offset = S.
Stk.
pop<T>();
2646 S, OpPC, Offset, Ptr,
true)) {
2653template <PrimType Name, class T = typename PrimConv<Name>::T>
2655 const T &Offset = S.
Stk.
pop<T>();
2659 S, OpPC, Offset, Ptr,
true)) {
2666template <ArithOp Op>
2682 OneT One = OneT::from(1);
2683 if (std::optional<Pointer>
Result =
2713template <PrimType Name, class T = typename PrimConv<Name>::T>
2722 if (!LHSAddrExpr || !RHSAddrExpr) {
2724 diag::note_constexpr_pointer_arith_unspecified)
2734 S.
Stk.
push<T>(LHSAddrExpr, RHSAddrExpr);
2743 diag::note_constexpr_pointer_arith_unspecified)
2749 if (ElemSize == 0) {
2754 diag::note_constexpr_pointer_subtraction_zero_size)
2772 assert(((int64_t)*VL - (int64_t)*VR) % ElemSize == 0);
2774 (
static_cast<int64_t
>(*VL) -
static_cast<int64_t
>(*VR)) / ElemSize;
2775 if (
static_cast<int64_t
>(T::from(R64)) != R64)
2807 auto In = S.
Stk.
pop<T>();
2821 if (!(U::bitWidth() >= 32 && U::bitWidth() <= In.bitWidth()))
2833 llvm::RoundingMode RM) {
2843 FixedPointSemantics::getFromOpaqueInt(FPS);
2858template <PrimType Name, class T = typename PrimConv<Name>::T>
2860 T Source = S.
Stk.
pop<T>();
2863 if (!Source.isNumber())
2870 APInt SourceInt = Source.toAPSInt().extOrTrunc(BitWidth);
2877template <PrimType Name, class T = typename PrimConv<Name>::T>
2879 T Source = S.
Stk.
pop<T>();
2882 if (!Source.isNumber())
2889 APInt SourceInt = Source.toAPSInt().extOrTrunc(BitWidth);
2898template <PrimType Name, class T = typename PrimConv<Name>::T>
2900 T Source = S.
Stk.
pop<T>();
2901 APSInt Val = Source.toAPSInt();
2902 if (Val.isNegative() || Val.getActiveBits() > 63)
2909template <PrimType Name, class T = typename PrimConv<Name>::T>
2911 const llvm::fltSemantics *Sem, uint32_t FPOI) {
2912 const T &From = S.
Stk.
pop<T>();
2915 if (!From.isNumber())
2919 APSInt FromAP = From.toAPSInt();
2930template <PrimType Name, class T = typename PrimConv<Name>::T>
2934 if constexpr (std::is_same_v<T, Boolean>) {
2943 if ((Status & APFloat::opStatus::opInvalidOp)) {
2962 const Pointer &Ptr,
unsigned BitWidth);
2967template <PrimType Name, class T = typename PrimConv<Name>::T>
2973 if constexpr (std::is_same_v<T, Boolean>) {
2988 PtrVal = Ptr.
block();
2991 S.
Stk.
push<T>(Kind, PtrVal, 0);
3004template <PrimType Name, class T = typename PrimConv<Name>::T>
3038 const llvm::fltSemantics *Sem) {
3041 Result.copy(Fixed.toFloat(Sem));
3046template <PrimType Name, class T = typename PrimConv<Name>::T>
3051 APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow);
3062 S.
CCEDiag(E, diag::note_constexpr_invalid_cast)
3063 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
3072 bool HasValidResult = !Ptr.isZero();
3074 if (HasValidResult) {
3081 E->getType()->getPointeeType()))
3084 S.
CCEDiag(E, diag::note_constexpr_invalid_void_star_cast)
3085 << E->getSubExpr()->getType() << S.
getLangOpts().CPlusPlus26
3086 << Ptr.getType().getCanonicalType() << E->getType()->getPointeeType();
3089 S.
CCEDiag(E, diag::note_constexpr_invalid_cast)
3090 << diag::ConstexprInvalidCastKind::CastFrom <<
"'void *'"
3095 S.
CCEDiag(E, diag::note_constexpr_invalid_cast)
3096 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
3107template <PrimType Name, class T = typename PrimConv<Name>::T>
3115 if (!
Result.singleWord())
3116 std::memset(
Result.Memory, 0,
Result.numWords() *
sizeof(uint64_t));
3123 if (!
Result.singleWord())
3124 std::memset(
Result.Memory, 0,
Result.numWords() *
sizeof(uint64_t));
3129template <PrimType Name, class T = typename PrimConv<Name>::T>
3137template <PrimType Name, class T = typename PrimConv<Name>::T>
3139 const auto &P = S.
Stk.
pop<T>();
3159 if (!
This.isDummy()) {
3161 if (!
This.isTypeidPointer()) {
3162 [[maybe_unused]]
const Record *R =
This.getRecord();
3164 R =
This.narrow().getRecord();
3167 assert(R->getDecl() ==
3189template <
class LT,
class RT, ShiftDir Dir>
3193 const unsigned Bits = LHS.bitWidth();
3197 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
3198 RHS.bitWidth(), &RHS);
3200 if (RHS.isNegative()) {
3204 S.
CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
3208 RHS = RHS.isMin() ? RT(APSInt::getMaxValue(RHS.bitWidth(),
false)) : -RHS;
3212 S, OpPC, LHS, RHS,
Result);
3224 typename LT::AsUnsigned R;
3225 unsigned MaxShiftAmount = LHS.bitWidth() - 1;
3227 if (
Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
3229 if (LHS.isNegative())
3230 R = LT::AsUnsigned::zero(LHS.bitWidth());
3232 RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth());
3233 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
3234 LT::AsUnsigned::from(RHS,
Bits),
Bits, &R);
3236 }
else if (LHS.isNegative()) {
3238 R = LT::AsUnsigned::zero(LHS.bitWidth());
3241 typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS);
3242 LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS,
Bits),
Bits,
3248 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
3249 LT::AsUnsigned::from(RHS,
Bits),
Bits, &R);
3256 if (
Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
3258 R = LT::AsUnsigned::from(0);
3262 LT::shiftRight(LHS, LT::from(RHS,
Bits),
Bits, &A);
3263 R = LT::AsUnsigned::from(A);
3271template <
class LT,
class RT, ShiftDir Dir>
3274 const unsigned Bits = LHS.getBitWidth();
3279 APSInt(llvm::APInt(RHS.getBitWidth(),
static_cast<uint64_t
>(
Bits - 1)),
3282 if (RHS.isNegative()) {
3286 S.
CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS;
3291 S, OpPC, LHS, -(RHS.extend(RHS.getBitWidth() + 1)),
Result);
3315template <PrimType NameL, PrimType NameR>
3319 auto RHS = S.
Stk.
pop<RT>();
3327 RHS.toAPSInt(), &
Result);
3334template <PrimType NameL, PrimType NameR>
3338 auto RHS = S.
Stk.
pop<RT>();
3346 RHS.toAPSInt(), &
Result);
3356 llvm::FixedPointSemantics LHSSema = LHS.
getSemantics();
3358 unsigned ShiftBitWidth =
3359 LHSSema.getWidth() - (
unsigned)LHSSema.hasUnsignedPadding() - 1;
3364 if (RHS.isNegative()) {
3367 }
else if (
static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(
3368 ShiftBitWidth)) != RHS.toAPSInt()) {
3370 S.
CCEDiag(E, diag::note_constexpr_large_shift)
3371 << RHS.toAPSInt() << E->
getType() << ShiftBitWidth;
3394 S.
FFDiag(EndLoc, diag::note_constexpr_no_return);
3425template <PrimType Name, class T = typename PrimConv<Name>::T>
3427 const T &Offset = S.
Stk.
pop<T>();
3430 if (!Ptr.isZero() && !Offset.isZero()) {
3435 if (Offset.isZero()) {
3436 if (
const Descriptor *Desc = Ptr.getFieldDesc();
3437 Desc && Desc->
isArray() && Ptr.getIndex() == 0) {
3445 assert(!Offset.isZero());
3447 if (std::optional<Pointer>
Result =
3456template <PrimType Name, class T = typename PrimConv<Name>::T>
3458 const T &Offset = S.
Stk.
pop<T>();
3461 if (!Ptr.isZero() && !Offset.isZero()) {
3466 if (Offset.isZero()) {
3467 if (
const Descriptor *Desc = Ptr.getFieldDesc();
3468 Desc && Desc->
isArray() && Ptr.getIndex() == 0) {
3476 assert(!Offset.isZero());
3478 if (std::optional<Pointer>
Result =
3486template <PrimType Name, class T = typename PrimConv<Name>::T>
3498template <PrimType Name, class T = typename PrimConv<Name>::T>
3510template <PrimType Name, class T = typename PrimConv<Name>::T>
3512 uint32_t DestIndex, uint32_t Size) {
3516 if (SrcPtr.isDummy() || DestPtr.
isDummy())
3522 const Descriptor *SrcDesc = SrcPtr.getFieldDesc();
3528 for (uint32_t I = 0; I != Size; ++I) {
3534 DestPtr.
elem<T>(DestIndex + I) = SrcPtr.elem<T>(SrcIndex + I);
3561 S.
FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
3572template <PrimType Name, class T = typename PrimConv<Name>::T>
3574 const T &IntVal = S.
Stk.
pop<T>();
3577 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
3582 if (IntVal.getOffset() != 0)
3588 if (IntVal.getOffset() != 0)
3591 const Block *B = (
const Block *)IntVal.getPtr();
3617 S.
FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)
3715 diag::note_constexpr_access_volatile_type)
3727 S.
CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
3735 diag::note_constexpr_pseudo_destructor);
3747 S.
CCEDiag(Loc, diag::note_constexpr_assumption_failed);
3751template <PrimType Name, class T = typename PrimConv<Name>::T>
3755 ArrayIndices.emplace_back(
3767template <PrimType Name, class T = typename PrimConv<Name>::T>
3769 const T &Arg = S.
Stk.
peek<T>();
3774 S.
CCEDiag(Loc, diag::note_non_null_attribute_failed);
3780 const APSInt &
Value);
3782template <PrimType Name, class T = typename PrimConv<Name>::T>
3800 const FromT &OldPtr = S.
Stk.
pop<FromT>();
3802 if constexpr (std::is_same_v<FromT, FunctionPointer> &&
3803 std::is_same_v<ToT, Pointer>) {
3806 }
else if constexpr (std::is_same_v<FromT, Pointer> &&
3807 std::is_same_v<ToT, FunctionPointer>) {
3808 if (OldPtr.isFunctionPointer()) {
3810 OldPtr.getByteOffset());
3815 S.
Stk.
push<ToT>(ToT(OldPtr.getIntegerRepresentation(),
nullptr));
3868template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
3883 if (NumElements.isNegative()) {
3893 if (!
CheckArraySize(S, OpPC,
static_cast<uint64_t
>(NumElements)))
3897 Block *B = Allocator.
allocate(Source, T,
static_cast<size_t>(NumElements),
3900 if (NumElements.isZero())
3907template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
3926 if (NumElements.isNegative()) {
3936 if (!
CheckArraySize(S, OpPC,
static_cast<uint64_t
>(NumElements)))
3940 Block *B = Allocator.
allocate(ElementDesc,
static_cast<size_t>(NumElements),
3943 if (NumElements.isZero())
3951bool Free(InterpState &S, CodePtr OpPC,
bool DeleteIsArrayForm,
3952 bool IsGlobalDelete);
3966 std::optional<uint64_t> ArraySize = std::nullopt);
3968template <PrimType Name, class T = typename PrimConv<Name>::T>
3970 const auto &Size = S.
Stk.
pop<T>();
3975template <PrimType Name, class T = typename PrimConv<Name>::T>
3977 uint32_t ResultBitWidth,
const llvm::fltSemantics *Sem,
3978 const Type *TargetType) {
3984 if constexpr (std::is_same_v<T, Pointer>) {
3987 diag::note_constexpr_bit_cast_invalid_type)
3988 <<
true <<
false << 1 ;
3994 }
else if constexpr (std::is_same_v<T, MemberPointer>) {
3996 diag::note_constexpr_bit_cast_invalid_type)
3997 <<
true <<
false << 2 ;
4001 size_t BuffSize = ResultBitWidth / 8;
4003 bool HasIndeterminateBits =
false;
4005 Bits FullBitWidth(ResultBitWidth);
4006 Bits BitWidth = FullBitWidth;
4008 if constexpr (std::is_same_v<T, Floating>) {
4010 BitWidth =
Bits(llvm::APFloatBase::getSizeInBits(*Sem));
4013 if (!
DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,
4014 HasIndeterminateBits))
4017 if (!
CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
4020 if constexpr (std::is_same_v<T, Floating>) {
4027 T::bitcastFromMemory(Buff.data(), ResultBitWidth, &
Result);
4029 }
else if constexpr (std::is_same_v<T, Boolean>) {
4033 auto Val =
static_cast<unsigned int>(Buff[0]);
4036 diag::note_constexpr_bit_cast_unrepresentable_value)
4040 S.
Stk.
push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
4043 S.
Stk.
push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
4054 if (D->isPrimitiveArray() && FromPtr.
isArrayRoot())
4069bool DiagTypeid(InterpState &S, CodePtr OpPC);
4081 if constexpr (std::is_pointer<T>::value) {
4082 uint32_t ID = OpPC.
read<uint32_t>();
4085 return OpPC.
read<T>();
4095 OpPC +=
align(F.bytesToSerialize());
4104 assert(
Result.bitWidth() == BitWidth);
4116 assert(
Result.bitWidth() == BitWidth);
Defines the clang::ASTContext interface.
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)
Result
Implement __builtin_bit_cast and related operations.
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.
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
bool hasSimilarType(QualType T1, QualType T2) const
Determine if two types are similar, according to the C++ rules.
AddrLabelExpr - The GNU address of label extension, representing &&label.
LabelDecl * getLabel() const
Represents a static or instance method of a struct/union/class.
Represents a C++ struct/union/class.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
unsigned getBuiltinCallee() const
getBuiltinCallee - If this is a call to a builtin, return the builtin ID of the callee.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
const ValueInfo * getValueInfo(ComparisonCategoryResult ValueKind) const
ComparisonCategoryResult makeWeakResult(ComparisonCategoryResult Res) const
Converts the specified result kind into the correct result kind for this category.
A reference to a declared variable, function, enum, etc.
Decl - This represents one declaration (or definition), e.g.
SourceLocation getEndLoc() const LLVM_READONLY
SourceLocation getLocation() const
DeclContext * getDeclContext()
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)
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.
Represents a function declaration or definition.
Implicit declaration of a temporary that was materialized by a MaterializeTemporaryExpr and lifetime-...
OffsetOfExpr - [C99 7.17] - This represents an expression of the form offsetof(record-type,...
unsigned getNumExpressions() const
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
QualType withVolatile() const
bool isWrapType() const
Returns true if it is a OverflowBehaviorType of Wrap kind.
Represents a struct/union/class.
Encodes a location in the source.
A trivial tuple used to represent a source range.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
The base class of the type hierarchy.
bool isNullPtrType() const
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.
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.
Block * allocate(const Descriptor *D, unsigned EvalID, Form AllocForm)
Allocate ONE element of the given descriptor.
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 FunctionDecl * getDecl() const
Returns the original FunctionDecl.
bool hasRVO() const
Checks if the first argument is a RVO pointer.
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)
Wrapper around numeric types.
static std::enable_if_t<!std::is_same_v< ValT, IntegralKind >, Integral > from(ValT V, unsigned NumBits=0)
Frame storing local variables.
static void free(InterpFrame *F)
const Expr * getExpr(CodePtr PC) const
bool isLocalEnabled(unsigned Idx) const
void setParam(unsigned Index, const T &Value)
Mutates a local copy of a parameter.
InterpFrame * Caller
The frame of the previous function.
SourceInfo getSource(CodePtr PC) const
Map a location to a source.
CodePtr getRetPC() const
Returns the return address of the frame.
void enableLocal(unsigned Idx)
Block * getLocalBlock(unsigned Offset) const
SourceLocation getLocation(CodePtr PC) const
const Pointer & getThis() const
Returns the 'this' pointer.
unsigned MSVCConstexprAllowed
const Function * getFunction() const
Returns the current function.
size_t getFrameOffset() const
Returns the offset on the stack at which the frame starts.
SourceRange getRange(CodePtr PC) const
void setLocal(unsigned Offset, const T &Value)
Mutates a local variable.
bool isBottomFrame() const
bool hasThisPointer() const
Pointer getLocalPointer(unsigned Offset) const
Returns a pointer to a local variables.
const T & getParam(unsigned Index) const
Returns the value of an argument.
const Pointer & getRVOPtr() const
Returns the RVO pointer, if the Function has one.
Pointer getParamPointer(unsigned Offset)
Returns a pointer to an argument - lazily creates a block.
const FunctionDecl * getCallee() const override
Returns the caller.
void initScope(unsigned Idx)
T pop()
Returns the value from the top of the stack and removes it.
void push(Tys &&...Args)
Constructs a value in place on the top of the stack.
void dump() const
dump the stack contents to stderr.
size_t size() const
Returns the size of the stack in bytes.
void discard()
Discards the top value from the stack.
T & peek() const
Returns a reference to the value on the top of the stack.
SmallVectorImpl< PartialDiagnosticAt > * PrevDiags
Things needed to do speculative execution.
DynamicAllocator & getAllocator()
Context & Ctx
Interpreter Context.
Floating allocFloat(const llvm::fltSemantics &Sem)
const unsigned EvalID
ID identifying this evaluation.
llvm::SmallVector< std::pair< const Expr *, const LifetimeExtendedTemporaryDecl * > > SeenGlobalTemporaries
InterpStack & Stk
Temporary stack.
bool maybeDiagnoseDanglingAllocations()
Diagnose any dynamic allocations that haven't been freed yet.
const VarDecl * EvaluatingDecl
Declaration we're initializing/evaluting, if any.
InterpFrame * Current
The current frame.
std::optional< bool > ConstantContextOverride
llvm::SmallVector< PtrView > InitializingPtrs
List of blocks we're currently running either constructors or destructors for.
T allocAP(unsigned BitWidth)
unsigned SpeculationDepth
StdAllocatorCaller getStdAllocatorCaller(StringRef Name) const
bool inConstantContext() const
Program & P
Reference to the module containing all bytecode.
unsigned getPathLength() const
Return the length of the cast path.
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.
Pointer stripBaseCasts() const
Strip base casts from this Pointer.
bool isInitialized() const
Checks if an object was initialized.
bool pointsToLabel() const
Whether this points to a block created for an AddrLabelExpr.
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.
const AddrLabelExpr * getPointedToLabel() const
Returns the AddrLabelExpr the Pointer points to, if any.
int64_t getIndex() const
Returns the index into an array.
bool canDeref(PrimType T) const
Checks whether the pointer can be dereferenced to the given PrimType.
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.
bool isIntegralPointer() const
QualType getType() const
Returns the type of the innermost field.
bool pointsToStringLiteral() const
void initialize() const
Initializes a field.
std::optional< size_t > computeOffsetForComparison(const ASTContext &ASTCtx) const
Compute an integer that can be used to compare this pointer to another one.
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
bool inArray() const
Checks if the innermost field is an array.
T & elem(unsigned I) const
Dereferences the element at index I.
std::optional< size_t > computeLayoutOffset(const ASTContext &ASTCtx) const
Compute the pointer offset as given by the ASTRecordLayout.
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.
bool isConstexprUnknown() const
const IntPointer & asIntPointer() const
bool isRoot() const
Pointer points directly to a block.
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
void activate() const
Activates a field.
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 isDereferencable() const
Whether this block can be read from at all.
bool isBlockPointer() const
const FunctionPointer & asFunctionPointer() const
const Block * block() const
void initializeElement(unsigned Index) const
Initialized the given element of a primitive array.
bool isFunctionPointer() const
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
bool canBeInitialized() const
If this pointer has an InlineDescriptor we can use to initialize.
const BlockPointer & asBlockPointer() const
static std::optional< std::pair< PtrView, PtrView > > computeSplitPoint(const Pointer &A, const Pointer &B)
const Record * getRecord() const
Returns the record descriptor of a class.
Function * getFunction(const FunctionDecl *F)
Returns a function.
Block * getGlobal(unsigned Idx)
Returns the value of a global.
UnsignedOrNone getOrCreateGlobal(const ValueDecl *VD, const Expr *Init=nullptr)
Returns or creates a global an creates an index to it.
Pointer getPtrGlobal(unsigned Idx) const
Returns a pointer to a global.
const void * getNativePointer(unsigned Idx) const
Returns the value of a marshalled native pointer.
Structure/Class descriptor.
bool isAnonymousUnion() const
Checks if the record is an anonymous union.
Describes the statement/declaration an opcode was generated from.
bool checkingForUndefinedBehavior() const
Are we checking an expression for overflow?
Expr::EvalStatus & getEvalStatus() const
DiagnosticBuilder report(SourceLocation Loc, diag::kind DiagId)
Directly reports a diagnostic message.
OptionalDiagnostic FFDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)
Diagnose that the evaluation could not be folded (FF => FoldFailure)
bool noteSideEffect() const
Note that we have had a side-effect, and determine whether we should keep evaluating.
ASTContext & getASTContext() const
bool noteUndefinedBehavior() const
Note that we hit something that was technically undefined behavior, but that we can evaluate past it ...
OptionalDiagnostic CCEDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)
Diagnose that the evaluation does not produce a C++11 core constant expression.
const LangOptions & getLangOpts() const
bool checkingPotentialConstantExpression() const
Are we checking whether the expression is a potential constant expression?
bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS, const Pointer &RHS)
static bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left)
bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off)
bool GetMemberPtrBase(InterpState &S)
bool PseudoDtor(InterpState &S, CodePtr OpPC)
Ends the lifetime of the pop'd pointer.
bool InitPop(InterpState &S, CodePtr OpPC)
bool Shr(InterpState &S, CodePtr OpPC)
bool CheckDestruction(InterpState &S, CodePtr OpPC)
bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index)
bool Flip(InterpState &S)
[Value1, Value2] -> [Value2, Value1]
bool GetTypeid(InterpState &S, const Type *TypePtr, const Type *TypeInfoType)
Typeid support.
bool GetLocalEnabled(InterpState &S, uint32_t I)
bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index)
bool GT(InterpState &S, CodePtr OpPC)
bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
bool GetPtrParam(InterpState &S, uint32_t Index)
bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
bool PushCC(InterpState &S, bool Value)
bool PreInc(InterpState &S, CodePtr OpPC, bool CanOverflow)
bool CheckFunctionDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *FD)
Opcode. Check if the function decl can be called at compile time.
bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I)
bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte, uint32_t ResultBitWidth, const llvm::fltSemantics *Sem, const Type *TargetType)
bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue)
Floating ReadArg< Floating >(InterpState &S, CodePtr &OpPC)
bool GetPtrLocal(InterpState &S, uint32_t I)
bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS, LT *Result)
bool StartThisLifetime(InterpState &S)
void cleanupAfterFunctionCall(InterpState &S, const Function *Func)
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc, AccessKinds AK)
Checks if the Descriptor is of a constexpr or const global variable.
bool Sub(InterpState &S, CodePtr OpPC)
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 LT(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 BitCast(InterpState &S, CodePtr OpPC)
bool LoadPop(InterpState &S, CodePtr OpPC)
bool SubPtr(InterpState &S, CodePtr OpPC, uint32_t ElemSize)
1) Pops a Pointer from the stack.
bool PushIgnoreDiags(InterpState &S)
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.
PRESERVE_NONE bool NoRet(InterpState &S)
bool InitBitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t FieldOffset, uint32_t FieldBitWidth)
bool CtorCheck(InterpState &S)
Abort without a diagnostic if we're checking for a potential constant expression and this is not the ...
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}...
bool CastMemberPtrDerivedPop(InterpState &S, int32_t Off, const RecordDecl *BaseDecl)
BaseToDerivedMemberPointer.
bool InitBitField(InterpState &S, CodePtr OpPC, uint32_t FieldOffset, uint32_t FieldBitWidth)
static bool IncDecPtrHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
bool CastNoOverflow(InterpState &S, CodePtr OpPC)
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.
static bool IsOpaqueConstantCall(const CallExpr *E)
bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, unsigned BitWidth)
bool CheckDecl(InterpState &S, const VarDecl *VD)
bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, const T &RHS)
bool EnableLocal(InterpState &S, uint32_t I)
bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off)
1) Peeks a Pointer 2) Pushes Pointer.atField(Off) on the stack
static bool CheckAllocations(InterpState &S)
bool StoreActivate(InterpState &S, CodePtr OpPC)
bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK, bool WillActivate)
bool Div(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
PRESERVE_NONE bool Ret(InterpState &S)
bool InitThisBitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t FieldOffset, uint32_t FieldBitWidth)
bool GetIntPtr(InterpState &S, CodePtr OpPC, const Type *Ty)
bool BitOr(InterpState &S)
1) Pops the RHS from the stack.
static bool CastFixedPointFloating(InterpState &S, const llvm::fltSemantics *Sem)
bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I)
Same as GetGlobal, but without the checks.
bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if Ptr is a one-past-the-end pointer.
bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC, const FixedPoint &FP)
bool PopIgnoreDiags(InterpState &S)
constexpr bool isIntegralOrPointer()
bool ArrayElemPtr(InterpState &S, CodePtr OpPC)
bool GetMemberPtrDecl(InterpState &S)
bool NE(InterpState &S, CodePtr OpPC)
bool handleReference(InterpState &S, CodePtr OpPC, Block *B)
bool StartSpeculation(InterpState &S)
bool CheckBitCast(InterpState &S, CodePtr OpPC, const Type *TargetType, bool SrcIsVoidPtr)
bool CopyMemberPtrPath(InterpState &S, const RecordDecl *Entry, bool IsDerived)
Just append the given Entry to the MemberPointer's path.
llvm::FixedPointSemantics FixedPointSemantics
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 ZeroIntAPS(InterpState &S, uint32_t BitWidth)
bool Shl(InterpState &S, CodePtr OpPC)
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 &IntResult)
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 CheckBCPResult(InterpState &S, const Pointer &Ptr)
bool SetLocal(InterpState &S, uint32_t I)
1) Pops the value from the stack.
PRESERVE_NONE bool EndSpeculation(InterpState &S)
bool diagnoseShiftFailure(InterpState &S, CodePtr OpPC, ShiftFailure Failure, const APSInt *Value, unsigned Bits)
bool GetFnPtr(InterpState &S, const Function *Func)
bool Store(InterpState &S, CodePtr OpPC)
bool Divc(InterpState &S, CodePtr OpPC)
bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr, Pointer &ToPtr)
bool GetField(InterpState &S, CodePtr OpPC, uint32_t I)
1) Peeks a pointer on the stack 2) Pushes the value of the pointer's field on the stack
bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC)
bool This(InterpState &S, CodePtr OpPC)
bool FinishInitActivate(InterpState &S)
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 Dump(InterpState &S)
bool FinishInitPop(InterpState &S)
bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn)
bool InitScope(InterpState &S, uint32_t I)
T ReadArg(InterpState &S, CodePtr &OpPC)
bool CastFP(InterpState &S, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
1) Pops a Floating from the stack.
bool PreDecBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow, uint32_t BitWidth)
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 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, const LifetimeExtendedTemporaryDecl *Temp)
1) Converts the value on top of the stack to an APValue 2) Sets that APValue on \Temp 3) Initialized ...
bool CheckRefInit(InterpState &S, CodePtr OpPC)
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E)
bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, unsigned Bits)
Checks if the shift operation is legal.
bool SetParam(InterpState &S, uint32_t I)
FixedPoint ReadArg< FixedPoint >(InterpState &S, CodePtr &OpPC)
bool IsNonNull(InterpState &S)
static bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, const APSInt &Value)
@ BlockAddress
A pointer to an interp::Block.
@ AddrLabelDiff
Difference between two AddrLabelExpr.
@ Number
Just a number, nothing else.
@ Address
A pointer to a ValueDecl.
@ LabelAddress
A pointer to a AddrLabelExpr.
@ FunctionAddress
A pointer to a FunctionDecl.
bool LE(InterpState &S, CodePtr OpPC)
bool isConstexprUnknown(const Block *B)
bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E)
bool StartThisLifetime1(InterpState &S)
bool RVOPtr(InterpState &S)
bool Unsupported(InterpState &S, CodePtr OpPC)
Just emit a diagnostic.
bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR, bool InitializerFailed)
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.
ComparisonCategoryResult Compare(const T &X, const T &Y)
Helper to compare two comparable types.
PrimType
Enumeration of the primitive types of the VM.
bool DecPopBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow, uint32_t BitWidth)
bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
bool StoreBitFieldPop(InterpState &S, CodePtr OpPC)
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool CanOverflow, UnsignedOrNone BitWidth=std::nullopt)
bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
static bool DecPtr(InterpState &S, CodePtr OpPC)
constexpr bool needsAlloc()
bool CastAPS(InterpState &S, uint32_t BitWidth)
bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index)
static bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
bool Rem(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
bool ExpandPtr(InterpState &S)
bool NarrowPtr(InterpState &S)
bool InitGlobalTemp(InterpState &S, 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 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 Mulc(InterpState &S)
bool checkDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
bool InitThisBitField(InterpState &S, CodePtr OpPC, uint32_t FieldOffset, uint32_t FieldBitWidth)
bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC)
static bool Activate(InterpState &S)
bool CheckRange(InterpState &S, CodePtr OpPC, PtrView Ptr, AccessKinds AK)
Checks if a pointer is in range.
static bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr)
bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T)
bool SideEffect(InterpState &S)
bool BitAnd(InterpState &S)
1) Pops the RHS from the stack.
bool GetRefGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
bool EndInit(InterpState &S)
PRESERVE_NONE bool RetVoid(InterpState &S)
bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
bool Comp(InterpState &S)
1) Pops the value from the stack.
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 CastAP(InterpState &S, uint32_t BitWidth)
Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need to know what bitwidth the resu...
bool IncBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow, unsigned BitWidth)
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)
bool StoreActivatePop(InterpState &S, CodePtr OpPC)
bool Null(InterpState &S, uint64_t Value, const Type *Ty)
bool StartInit(InterpState &S)
bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool GetRefLocal(InterpState &S, CodePtr OpPC, uint32_t I)
bool CheckThis(InterpState &S, CodePtr OpPC)
Checks the 'this' pointer.
static bool ActivateThisField(InterpState &S, uint32_t I)
bool Const(InterpState &S, const T &Arg)
bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)
bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC, const RecordDecl *D)
bool StorePop(InterpState &S, CodePtr OpPC)
bool CheckIntegralAddressCast(InterpState &S, CodePtr OpPC, unsigned BitWidth)
bool InvalidStore(InterpState &S, CodePtr OpPC, const Type *T)
bool ConstFloat(InterpState &S, const Floating &F)
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)
static bool IsConstantContext(InterpState &S)
bool DecBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow, uint32_t BitWidth)
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
bool ToMemberPtr(InterpState &S)
bool PreIncBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow, uint32_t BitWidth)
bool Dec(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 StoreBitFieldActivate(InterpState &S, CodePtr OpPC)
bool BitXor(InterpState &S)
1) Pops the RHS from the stack.
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 InitGlobal(InterpState &S, uint32_t I)
bool CheckArrayDestSize(InterpState &S, CodePtr OpPC, size_t NumElems)
Check if the destination array we're initializing can hold the NumElems elements.
bool CallBI(InterpState &S, CodePtr OpPC, const CallExpr *CE, uint32_t BuiltinID)
bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B)
bool Neg(InterpState &S, CodePtr OpPC)
bool DecayPtr(InterpState &S)
OldPtr -> Integer -> NewPtr.
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 FinishInit(InterpState &S)
llvm::function_ref< bool(ComparisonCategoryResult)> CompareFn
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool WillBeActivated)
Checks if a value can be stored in a block.
bool Load(InterpState &S, CodePtr OpPC)
bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
bool Cast(InterpState &S, CodePtr OpPC)
bool StoreBitFieldActivatePop(InterpState &S, CodePtr OpPC)
bool Inc(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 FinishInitGlobal(InterpState &S)
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 Add(InterpState &S, CodePtr OpPC)
bool CmpHelperEQ< MemberPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
bool AddOffset(InterpState &S, CodePtr OpPC)
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 ...
constexpr bool isIntegerType(PrimType T)
static bool AddSubNonNumber(InterpState &S, CodePtr OpPC, T LHS, T RHS)
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)
bool PushMSVCCE(InterpState &S)
bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)
static bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC)
bool MarkDestroyed(InterpState &S, CodePtr OpPC)
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 PopMSVCCE(InterpState &S)
bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc, bool IsNoThrow)
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool GetMemberPtr(InterpState &S, const ValueDecl *D)
bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
bool CastMemberPtrBasePop(InterpState &S, int32_t Off, const RecordDecl *BaseDecl)
DerivedToBaseMemberPointer.
bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, bool Fatal)
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 VirtBaseHelper(InterpState &S, const RecordDecl *Decl, const Pointer &Ptr)
bool InitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I)
bool IncPopBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow, uint32_t BitWidth)
bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo)
bool Invalid(InterpState &S, CodePtr OpPC)
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 PopCC(InterpState &S)
bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off)
bool GetParam(InterpState &S, uint32_t Index)
bool GetPtrGlobal(InterpState &S, uint32_t I)
bool FinishInitActivatePop(InterpState &S)
bool DynamicCast(InterpState &S, CodePtr OpPC, const Type *DestTypePtr, bool IsReferenceCast)
bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t FPOI)
bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source, bool IsNoThrow)
bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED)
static bool ZeroIntAP(InterpState &S, uint32_t BitWidth)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
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.
OptionalUnsigned< unsigned > UnsignedOrNone
@ Off
Never emit colors regardless of the output stream.
@ ConstantFold
Fold the expression to a constant.
U cast(CodeGen::Address addr)
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 __packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 uint32_t
SmallVectorImpl< PartialDiagnosticAt > * Diag
Diag - If this is non-null, it will be filled in with a stack of notes indicating why evaluation fail...
bool DiagEmitted
Whether any diagnostic has been emitted.
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 getNumElems() const
Returns the number of elements stored in the block.
unsigned getSize() const
Returns the size of the object without metadata.
const Decl * asDecl() const
bool isUnknownSizeArray() const
Checks if the descriptor is of an array of unknown size.
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
const VarDecl * asVarDecl() const
PrimType getPrimType() const
bool isRecord() const
Checks if the descriptor is of a record.
const Expr * asExpr() const
bool isArray() const
Checks if the descriptor is of an array.
Descriptor used for global variables.
QualType getPointeeType() const
Mapping from primitive types to their representation.