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/Support/Compiler.h"
44#if !defined(__aarch64__) && !defined(__i386__) && \
45 !__has_feature(address_sanitizer) && \
46 __has_cpp_attribute(clang::preserve_none)
47#define PRESERVE_NONE [[clang::preserve_none]]
55using APSInt = llvm::APSInt;
84 std::optional<uint64_t> NumElems = std::nullopt,
116 uint32_t VarArgSize);
118 uint32_t VarArgSize);
120 uint32_t VarArgSize);
128 bool TargetIsUCharOrByte);
144 bool IsReferenceCast);
161 const APSInt *
Value =
nullptr,
165template <ShiftDir Dir,
typename LT,
typename RT>
168 if (RHS.isNegative()) {
183 if (LHS.isSigned() && !S.
getLangOpts().CPlusPlus20) {
186 if (LHS.isNegative()) {
191 }
else if (LHS.toUnsigned().countLeadingZeros() <
192 static_cast<unsigned>(RHS)) {
210 if (!LHS.isNumber() || !RHS.isNumber())
216 if constexpr (std::is_same_v<T, Floating>) {
217 S.
CCEDiag(Op, diag::note_expr_divide_by_zero)
218 << Op->getRHS()->getSourceRange();
222 S.
FFDiag(Op, diag::note_expr_divide_by_zero)
223 << Op->getRHS()->getSourceRange();
227 if constexpr (!std::is_same_v<T, FixedPoint>) {
228 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
229 APSInt LHSInt = LHS.toAPSInt();
231 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
234 S.
CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->
getType();
255 APFloat::opStatus Status,
FPOptions FPO);
260bool CheckFloatStatus(InterpState &S, CodePtr OpPC, APFloat::opStatus Status,
282template <PrimType Name, class T = typename PrimConv<Name>::T>
321 template <typename U>
class OpAP>
326 assert(LHS.isNumber() && RHS.isNumber());
342 if constexpr (std::is_same_v<T, FixedPoint>)
358 .toString(Trunc, 10,
Result.isSigned(),
false,
372template <
typename T,
template <
typename U>
class Op>
374 assert(!LHS.isNumber() || !RHS.isNumber());
378 typename T::ReprT Offset;
380 if (LHS.isNumber()) {
384 Number =
static_cast<typename T::ReprT
>(LHS);
386 Offset = RHS.getOffset();
387 Kind = RHS.getKind();
389 assert(RHS.isNumber());
393 Number =
static_cast<typename T::ReprT
>(RHS);
395 Offset = LHS.getOffset();
396 Kind = LHS.getKind();
403template <PrimType Name, class T = typename PrimConv<Name>::T>
407 const unsigned Bits = RHS.bitWidth() + 1;
410 if (LHS.isNumber() != RHS.isNumber())
412 else if (LHS.isNumber() && RHS.isNumber())
432template <PrimType Name, class T = typename PrimConv<Name>::T>
436 const unsigned Bits = RHS.bitWidth() + 1;
445 ?
reinterpret_cast<const Expr *
>(LHS.getPtr())
448 ?
reinterpret_cast<const Expr *
>(RHS.getPtr())
450 if (!isa_and_nonnull<AddrLabelExpr>(A) ||
451 !isa_and_nonnull<AddrLabelExpr>(B))
456 if (LHSAddrExpr->getLabel()->getDeclContext() !=
457 RHSAddrExpr->getLabel()->getDeclContext())
460 S.
Stk.
push<
T>(LHSAddrExpr, RHSAddrExpr);
464 if (!LHS.isNumber() && RHS.isNumber())
466 else if (LHS.isNumber() && RHS.isNumber())
486template <PrimType Name, class T = typename PrimConv<Name>::T>
490 const unsigned Bits = RHS.bitWidth() * 2;
493 if (!LHS.isNumber() || !RHS.isNumber())
513template <PrimType Name, class T = typename PrimConv<Name>::T>
519 if constexpr (std::is_same_v<T, Floating>) {
525 APFloat ResR(A.getSemantics());
526 APFloat ResI(A.getSemantics());
537 Result.initializeAllElements();
540 const T &LHSR = LHS.elem<
T>(0);
541 const T &LHSI = LHS.elem<
T>(1);
542 const T &RHSR = RHS.
elem<
T>(0);
543 const T &RHSI = RHS.
elem<
T>(1);
544 unsigned Bits = LHSR.bitWidth();
547 if (!LHSR.isNumber() || !LHSI.isNumber() || !RHSR.isNumber() ||
555 if (T::mul(LHSR, RHSR,
Bits, &A))
561 if (T::mul(LHSI, RHSI,
Bits, &B))
570 if (T::mul(LHSR, RHSI,
Bits, &A))
572 if (T::mul(LHSI, RHSR,
Bits, &B))
580 Result.initializeAllElements();
586template <PrimType Name, class T = typename PrimConv<Name>::T>
592 if constexpr (std::is_same_v<T, Floating>) {
598 APFloat ResR(A.getSemantics());
599 APFloat ResI(A.getSemantics());
611 Result.initializeAllElements();
614 const T &LHSR = LHS.elem<
T>(0);
615 const T &LHSI = LHS.elem<
T>(1);
616 const T &RHSR = RHS.
elem<
T>(0);
617 const T &RHSI = RHS.
elem<
T>(1);
618 unsigned Bits = LHSR.bitWidth();
620 if (RHSR.isZero() && RHSI.isZero()) {
622 S.
FFDiag(E, diag::note_expr_divide_by_zero);
633 if (T::mul(RHSR, RHSR,
Bits, &A) || T::mul(RHSI, RHSI,
Bits, &B)) {
640 if (T::add(A, B,
Bits, &Den))
645 S.
FFDiag(E, diag::note_expr_divide_by_zero);
656 if (T::mul(LHSR, RHSR,
Bits, &A) || T::mul(LHSI, RHSI,
Bits, &B))
658 if (T::add(A, B,
Bits, &ResultR))
660 if (T::div(ResultR, Den,
Bits, &ResultR))
664 if (T::mul(LHSI, RHSR,
Bits, &A) || T::mul(LHSR, RHSI,
Bits, &B))
666 if (T::sub(A, B,
Bits, &ResultI))
668 if (T::div(ResultI, Den,
Bits, &ResultI))
670 Result.initializeAllElements();
679template <PrimType Name, class T = typename PrimConv<Name>::T>
683 unsigned Bits = RHS.bitWidth();
686 if (!LHS.isNumber() || !RHS.isNumber())
704template <PrimType Name, class T = typename PrimConv<Name>::T>
708 unsigned Bits = RHS.bitWidth();
711 if (!LHS.isNumber() || !RHS.isNumber())
729template <PrimType Name, class T = typename PrimConv<Name>::T>
733 unsigned Bits = RHS.bitWidth();
736 if (!LHS.isNumber() || !RHS.isNumber())
754template <PrimType Name, class T = typename PrimConv<Name>::T>
758 const unsigned Bits = RHS.bitWidth() * 2;
777template <PrimType Name, class T = typename PrimConv<Name>::T>
781 const unsigned Bits = RHS.bitWidth() * 2;
795 if constexpr (std::is_same_v<T, FixedPoint>) {
834template <PrimType Name, class T = typename PrimConv<Name>::T>
838 if constexpr (std::is_same_v<T, Floating>) {
857 "don't expect other types to fail at constexpr negation");
868 NegatedValue.trunc(
Result.bitWidth())
869 .toString(Trunc, 10,
Result.isSigned(),
false,
889template <
typename T, IncDecOp Op, PushVal DoPush>
892 assert(!Ptr.isDummy());
899 if constexpr (std::is_same_v<T, Boolean>) {
904 const T &
Value = Ptr.deref<
T>();
908 if (!
Value.isNumber())
920 if (!T::increment(
Value, &
Result) || !CanOverflow) {
922 Ptr.deref<
T>() =
Result.truncate(*BitWidth);
928 if (!T::decrement(
Value, &
Result) || !CanOverflow) {
930 Ptr.deref<
T>() =
Result.truncate(*BitWidth);
957 APResult.trunc(
Result.bitWidth())
958 .toString(Trunc, 10,
Result.isSigned(),
false,
971template <PrimType Name, class T = typename PrimConv<Name>::T>
983template <PrimType Name, class T = typename PrimConv<Name>::T>
999template <PrimType Name, class T = typename PrimConv<Name>::T>
1010template <PrimType Name, class T = typename PrimConv<Name>::T>
1012 uint32_t BitWidth) {
1023template <PrimType Name, class T = typename PrimConv<Name>::T>
1034template <PrimType Name, class T = typename PrimConv<Name>::T>
1036 uint32_t BitWidth) {
1051template <PrimType Name, class T = typename PrimConv<Name>::T>
1062template <PrimType Name, class T = typename PrimConv<Name>::T>
1064 uint32_t BitWidth) {
1078template <PrimType Name, class T = typename PrimConv<Name>::T>
1089template <PrimType Name, class T = typename PrimConv<Name>::T>
1091 uint32_t BitWidth) {
1102template <PrimType Name, class T = typename PrimConv<Name>::T>
1112template <PrimType Name, class T = typename PrimConv<Name>::T>
1114 uint32_t BitWidth) {
1124template <IncDecOp Op, PushVal DoPush>
1134 llvm::APFloat::opStatus Status;
1187template <PrimType Name, class T = typename PrimConv<Name>::T>
1195 if (!T::comp(Val, &
Result)) {
1208template <
typename T>
1210 assert((!std::is_same_v<T, MemberPointer>) &&
1211 "Non-equality comparisons on member pointer types should already be "
1212 "rejected in Sema.");
1218 if (!LHS.isNumber() || !RHS.isNumber())
1222 S.
Stk.
push<BoolT>(BoolT::from(
Fn(LHS.compare(RHS))));
1226template <
typename T>
1241 S.
FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1254 S.
FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1262 if (std::optional<std::pair<PtrView, PtrView>> Split =
1264 const FieldDecl *LF = Split->first.getField();
1265 const FieldDecl *RF = Split->second.getField();
1268 diag::note_constexpr_pointer_comparison_base_classes);
1271 diag::note_constexpr_pointer_comparison_base_field)
1272 << Split->first.getRecord()->getDecl() << RF->
getParent() << RF;
1275 diag::note_constexpr_pointer_comparison_base_field)
1276 << Split->second.getRecord()->getDecl() << LF->
getParent() << LF;
1280 diag::note_constexpr_pointer_comparison_differing_access)
1295 return (
Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
1296 Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
1297 Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||
1298 Builtin == Builtin::BI__builtin_function_start);
1310 if (LHS.isZero() && RHS.
isZero()) {
1316 for (
const auto &P : {LHS, RHS}) {
1321 S.
FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
1328 if (RHS.
isZero() || LHS.isZero()) {
1333 assert(!LHS.isZero());
1348 std::optional<size_t> A = LHS.computeOffsetForComparison(S.
getASTContext());
1361 diag::note_constexpr_literal_comparison)
1369 S.
FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
1375 S.
FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
1381 for (
const auto &P : {LHS, RHS}) {
1384 if (P.pointsToLiteral()) {
1385 const Expr *E = P.getRootExpr();
1388 S.
FFDiag(Loc, diag::note_constexpr_literal_comparison);
1391 if (
const auto *CE = dyn_cast<CallExpr>(E);
1394 S.
FFDiag(Loc, diag::note_constexpr_opaque_call_comparison)
1398 }
else if (P.isIntegralPointer()) {
1400 S.
FFDiag(Loc, diag::note_constexpr_pointer_constant_comparison)
1409 S.
FFDiag(Loc, diag::note_constexpr_pointer_comparison_zero_sized)
1418 diag::note_constexpr_pointer_comparison_unspecified)
1436 for (
const auto &MP : {LHS, RHS}) {
1439 S.
FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison)
1440 << MP.getMemberFunction();
1448 if (LHS.
isZero() && RHS.isZero()) {
1452 if (LHS.
isZero() || RHS.isZero()) {
1458 for (
const auto &MP : {LHS, RHS}) {
1462 S.
CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
1470template <PrimType Name, class T = typename PrimConv<Name>::T>
1477template <PrimType Name, class T = typename PrimConv<Name>::T>
1484 if constexpr (std::is_same_v<T, Pointer>) {
1487 diag::note_constexpr_pointer_comparison_unspecified)
1492 std::optional<size_t> LHSOffset =
1494 std::optional<size_t> RHSOffset =
1496 if (!LHSOffset || !RHSOffset)
1499 if (LHSOffset < RHSOffset)
1501 else if (LHSOffset > RHSOffset)
1506 CmpResult = LHS.compare(RHS);
1510 const auto *CmpValueInfo =
1512 assert(CmpValueInfo);
1513 assert(CmpValueInfo->hasValidIntValue());
1517template <PrimType Name, class T = typename PrimConv<Name>::T>
1524template <PrimType Name, class T = typename PrimConv<Name>::T>
1531template <PrimType Name, class T = typename PrimConv<Name>::T>
1539template <PrimType Name, class T = typename PrimConv<Name>::T>
1546template <PrimType Name, class T = typename PrimConv<Name>::T>
1558template <PrimType Name, class T = typename PrimConv<Name>::T>
1564template <PrimType Name, class T = typename PrimConv<Name>::T>
1575 const auto &Top = S.
Stk.
pop<TopT>();
1576 const auto &Bottom = S.
Stk.
pop<BottomT>();
1588template <PrimType Name, class T = typename PrimConv<Name>::T>
1592 Result.copy(Arg.toAPSInt());
1597 if constexpr (std::is_same_v<T, uint16_t>) {
1599 }
else if constexpr (std::is_same_v<T, int16_t>) {
1601 }
else if constexpr (std::is_same_v<T, uint32_t>) {
1603 }
else if constexpr (std::is_same_v<T, int32_t>) {
1605 }
else if constexpr (std::is_same_v<T, uint64_t>) {
1607 }
else if constexpr (std::is_same_v<T, int64_t>) {
1628template <PrimType Name, class T = typename PrimConv<Name>::T>
1638bool PseudoDtor(InterpState &S, CodePtr OpPC);
1647template <PrimType Name, class T = typename PrimConv<Name>::T>
1653template <PrimType Name, class T = typename PrimConv<Name>::T>
1662template <PrimType Name, class T = typename PrimConv<Name>::T>
1670template <PrimType Name, class T = typename PrimConv<Name>::T>
1696template <PrimType Name, class T = typename PrimConv<Name>::T>
1720template <PrimType Name, class T = typename PrimConv<Name>::T>
1728 if (!
This.isBlockPointer())
1738template <PrimType Name, class T = typename PrimConv<Name>::T>
1750template <PrimType Name, class T = typename PrimConv<Name>::T>
1761template <PrimType Name, class T = typename PrimConv<Name>::T>
1767template <PrimType Name, class T = typename PrimConv<Name>::T>
1773 if constexpr (std::is_same_v<T, Floating>) {
1775 if (!Val.singleWord()) {
1776 uint64_t *NewMemory =
new (S.
P) uint64_t[Val.numWords()];
1777 Val.take(NewMemory);
1780 }
else if constexpr (std::is_same_v<T, MemberPointer>) {
1784 for (
unsigned I = 0; I != PathLength; ++I) {
1785 NewPath[I] = Val.getPathEntry(I);
1787 Val.takePath(NewPath);
1788 }
else if constexpr (std::is_same_v<T, Pointer>) {
1790 if (Val.isOpaquePointer() && Val.asOpaquePointer().PathLength != 0) {
1797 Val.getByteOffset());
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>
1823 assert(Ptr.getRootExpr());
1845template <PrimType Name, class T = typename PrimConv<Name>::T>
1852 if (!
This.isDereferencable())
1856 assert(Field.canBeInitialized());
1862template <PrimType Name, class T = typename PrimConv<Name>::T>
1869 if (!
This.isDereferencable())
1873 assert(Field.canBeInitialized());
1880template <PrimType Name, class T = typename PrimConv<Name>::T>
1882 uint32_t FieldBitWidth) {
1888 if (!
This.isDereferencable())
1892 assert(Field.canBeInitialized());
1896 if (!
Value.isNumber())
1900 Field.deref<
T>() =
Value.truncate(FieldBitWidth);
1905template <PrimType Name, class T = typename PrimConv<Name>::T>
1907 uint32_t FieldOffset, uint32_t FieldBitWidth) {
1913 if (!
This.isDereferencable())
1917 assert(Field.canBeInitialized());
1921 if (!
Value.isNumber())
1925 Field.deref<
T>() =
Value.truncate(FieldBitWidth);
1934template <PrimType Name, class T = typename PrimConv<Name>::T>
1938 if (!Ptr.isDereferencable())
1946 const Pointer &Field = Ptr.atField(I);
1947 Field.deref<
T>() =
Value;
1952template <PrimType Name, class T = typename PrimConv<Name>::T>
1956 if (!Ptr.isDereferencable())
1963 const Pointer &Field = Ptr.atField(I);
1964 Field.deref<
T>() =
Value;
1970template <PrimType Name, class T = typename PrimConv<Name>::T>
1972 uint32_t FieldBitWidth) {
1975 if (!Ptr.isDereferencable())
1979 if (!
Value.isNumber())
1987 const Pointer &Field = Ptr.atField(FieldOffset);
1989 unsigned BitWidth = std::min(FieldBitWidth,
Value.bitWidth());
1992 if constexpr (T::isSigned())
1994 Value.toAPSInt().trunc(BitWidth).sextOrTrunc(
Value.bitWidth()));
1997 Value.toAPSInt().trunc(BitWidth).zextOrTrunc(
Value.bitWidth()));
2001 Field.deref<
T>() =
Value.truncate(FieldBitWidth);
2007template <PrimType Name, class T = typename PrimConv<Name>::T>
2009 uint32_t FieldBitWidth) {
2012 if (!Ptr.isDereferencable())
2016 if (!
Value.isNumber())
2024 const Pointer &Field = Ptr.atField(FieldOffset);
2026 unsigned BitWidth = std::min(FieldBitWidth,
Value.bitWidth());
2029 if constexpr (T::isSigned())
2031 Value.toAPSInt().trunc(BitWidth).sextOrTrunc(
Value.bitWidth()));
2034 Value.toAPSInt().trunc(BitWidth).zextOrTrunc(
Value.bitWidth()));
2038 Field.deref<
T>() =
Value.truncate(FieldBitWidth);
2106bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t
Off,
bool NullOK);
2109 const Type *TargetType);
2117 if (!
This.isBlockPointer())
2135 if (Ptr.canBeInitialized())
2142 if (Ptr.canBeInitialized())
2149 if (Ptr.canBeInitialized()) {
2158 if (Ptr.canBeInitialized()) {
2176 diag::note_constexpr_dereferencing_null);
2218template <PrimType Name, class T = typename PrimConv<Name>::T>
2223 if (!Ptr.canDeref(Name))
2229template <PrimType Name, class T = typename PrimConv<Name>::T>
2234 if (!Ptr.canDeref(Name))
2247 bool Failed =
false;
2250 if (!Ptr.isBlockPointer())
2252 if (!Failed && !Ptr.canDeref(
PT_Ptr))
2257 if (Ptr.isOpaquePointer()) {
2260 if (!Ptr.asOpaquePointer().Base.getType()->isPointerType())
2265 Ptr.getByteOffset());
2270 if (!Ptr.isBlockPointer())
2280template <PrimType Name, class T = typename PrimConv<Name>::T>
2286 if (!Ptr.canDeref(Name))
2288 if (Ptr.canBeInitialized())
2294template <PrimType Name, class T = typename PrimConv<Name>::T>
2300 if (!Ptr.canDeref(Name))
2302 if (Ptr.canBeInitialized())
2310 if (Ptr.canBeInitialized())
2322 assert(Ptr.atField(I).canBeInitialized());
2323 Ptr.atField(I).activate();
2327template <PrimType Name, class T = typename PrimConv<Name>::T>
2334 if (Ptr.canBeInitialized()) {
2342template <PrimType Name, class T = typename PrimConv<Name>::T>
2349 if (Ptr.canBeInitialized()) {
2357template <PrimType Name, class T = typename PrimConv<Name>::T>
2364 if (Ptr.canBeInitialized())
2366 if (
const auto *FD = Ptr.getField())
2367 Ptr.deref<
T>() =
Value.truncate(FD->getBitWidthValue());
2373template <PrimType Name, class T = typename PrimConv<Name>::T>
2379 if (Ptr.canBeInitialized())
2381 if (
const auto *FD = Ptr.getField())
2382 Ptr.deref<
T>() =
Value.truncate(FD->getBitWidthValue());
2388template <PrimType Name, class T = typename PrimConv<Name>::T>
2395 if (Ptr.canBeInitialized()) {
2399 if (
const auto *FD = Ptr.getField())
2400 Ptr.deref<
T>() =
Value.truncate(FD->getBitWidthValue());
2406template <PrimType Name, class T = typename PrimConv<Name>::T>
2413 if (Ptr.canBeInitialized()) {
2417 if (
const auto *FD = Ptr.getField())
2418 Ptr.deref<
T>() =
Value.truncate(FD->getBitWidthValue());
2424template <PrimType Name, class T = typename PrimConv<Name>::T>
2431 new (&Ptr.deref<
T>())
T(
Value);
2435template <PrimType Name, class T = typename PrimConv<Name>::T>
2442 new (&Ptr.deref<
T>())
T(
Value);
2449template <PrimType Name, class T = typename PrimConv<Name>::T>
2454 if (Ptr.isConstexprUnknown())
2463 if (Idx == 0 && !Desc->
isArray()) {
2465 new (&Ptr.deref<
T>())
T(
Value);
2475 S.
FFDiag(Loc, diag::note_constexpr_access_past_end)
2480 Ptr.initializeElement(Idx);
2481 new (&Ptr.elem<
T>(Idx))
T(
Value);
2486template <PrimType Name, class T = typename PrimConv<Name>::T>
2491 if (Ptr.isConstexprUnknown())
2500 if (Idx == 0 && !Desc->
isArray()) {
2502 new (&Ptr.deref<
T>())
T(
Value);
2512 S.
FFDiag(Loc, diag::note_constexpr_access_past_end)
2517 Ptr.initializeElement(Idx);
2518 new (&Ptr.elem<
T>(Idx))
T(
Value);
2533 if (std::optional<Pointer> Ptr = MP.toPointer(S.
Ctx)) {
2540bool Memcpy(InterpState &S, CodePtr OpPC);
2548template <
class T, ArithOp Op>
2550 const T &Offset,
const Pointer &Ptr,
2551 bool IsPointerArith =
false) {
2553 if (Offset.isZero())
2560 return std::nullopt;
2565 return std::nullopt;
2568 if (Ptr.isIntegralPointer()) {
2569 uint64_t
V = Ptr.getIntegerRepresentation();
2570 QualType ElemType = Ptr.asIntPointer().getPointeeType();
2575 uint64_t O =
static_cast<uint64_t
>(Offset) * ElemSize;
2577 return Pointer(
V + O, Ptr.asIntPointer().getType());
2579 return Pointer(
V - O, Ptr.asIntPointer().getType());
2580 }
else if (Ptr.isFunctionPointer()) {
2581 uint64_t O =
static_cast<uint64_t
>(Offset);
2584 N = Ptr.getByteOffset() + O;
2586 N = Ptr.getByteOffset() - O;
2590 return Pointer(Ptr.asFunctionPointer().Func, N);
2591 }
else if (Ptr.isStringPointer()) {
2594 NewOffset = Ptr.getByteOffset() +
static_cast<int64_t
>(Offset);
2596 NewOffset = Ptr.getByteOffset() -
static_cast<int64_t
>(Offset);
2597 if (NewOffset < 0 ||
2598 NewOffset > (Ptr.asStringPointer().getLiteral()->getLength() + 1)) {
2600 (Ptr.asStringPointer().getLiteral()->getLength() + 1));
2601 return std::nullopt;
2603 return Pointer(Ptr.asStringPointer(), NewOffset);
2604 }
else if (!Ptr.isBlockPointer()) {
2605 return std::nullopt;
2608 assert(Ptr.isBlockPointer());
2610 uint64_t MaxIndex =
static_cast<uint64_t
>(Ptr.getNumElems());
2612 if (Ptr.isOnePastEnd())
2615 Index = Ptr.getIndex();
2619 auto DiagInvalidOffset = [&]() ->
void {
2620 const unsigned Bits = Offset.bitWidth();
2621 APSInt APOffset(Offset.toAPSInt().extend(
Bits + 2),
false);
2625 (Op ==
ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
2630 uint64_t IOffset =
static_cast<uint64_t
>(Offset);
2631 uint64_t MaxOffset = MaxIndex - Index;
2635 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
2636 DiagInvalidOffset();
2639 if (Offset.isPositive() && IOffset > MaxOffset)
2640 DiagInvalidOffset();
2643 if (Offset.isPositive() && Index < IOffset)
2644 DiagInvalidOffset();
2647 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
2648 DiagInvalidOffset();
2652 return std::nullopt;
2655 int64_t WideIndex =
static_cast<int64_t
>(Index);
2656 int64_t WideOffset =
static_cast<int64_t
>(Offset);
2659 Result = WideIndex + WideOffset;
2661 Result = WideIndex - WideOffset;
2666 if (
Result == 0 && Ptr.isOnePastEnd()) {
2667 if (Ptr.getFieldDesc()->isArray())
2668 return Ptr.atIndex(0);
2669 return Pointer(Ptr.asBlockPointer().Pointee, Ptr.asBlockPointer().Base);
2672 return Ptr.atIndex(
static_cast<uint64_t
>(
Result));
2676 const Pointer &Ptr, APSInt &&Offset,
2678template <PrimType Name, class T = typename PrimConv<Name>::T>
2683 if (Ptr.isOpaquePointer()) {
2684 if (std::optional<Pointer>
Result =
2693 S, OpPC, Offset, Ptr,
true)) {
2700template <PrimType Name, class T = typename PrimConv<Name>::T>
2705 if (Ptr.isOpaquePointer()) {
2706 if (std::optional<Pointer>
Result =
2715 S, OpPC, Offset, Ptr,
true)) {
2723 bool ConstexprUnknown) {
2728template <ArithOp Op>
2731 if (!Ptr.isDereferencable())
2744 if (std::optional<Pointer>
Result =
2753 OneT One = OneT::from(1);
2754 if (std::optional<Pointer>
Result =
2766 if (!Ptr.isInitialized())
2775 if (!Ptr.isInitialized())
2784template <PrimType Name, class T = typename PrimConv<Name>::T>
2793 if (!LHSAddrExpr || !RHSAddrExpr) {
2795 diag::note_constexpr_pointer_arith_unspecified)
2805 S.
Stk.
push<
T>(LHSAddrExpr, RHSAddrExpr);
2814 diag::note_constexpr_pointer_arith_unspecified)
2820 if (ElemSize == 0) {
2825 diag::note_constexpr_pointer_subtraction_zero_size)
2842 diag::note_constexpr_pointer_subtraction_not_same_array);
2854 (
static_cast<int64_t
>(*VL) -
static_cast<int64_t
>(*VR)) / ElemSize;
2855 if (
static_cast<int64_t
>(T::from(R64)) != R64)
2901 if (!(U::bitWidth() >= 32 && U::bitWidth() <= In.bitWidth()))
2913 llvm::RoundingMode RM) {
2923 FixedPointSemantics::getFromOpaqueInt(FPS);
2938template <PrimType Name, class T = typename PrimConv<Name>::T>
2943 if (!Source.isNumber())
2950 APInt SourceInt = Source.toAPSInt().extOrTrunc(BitWidth);
2957template <PrimType Name, class T = typename PrimConv<Name>::T>
2962 if (!Source.isNumber())
2969 APInt SourceInt = Source.toAPSInt().extOrTrunc(BitWidth);
2979template <PrimType Name, class T = typename PrimConv<Name>::T>
2982 APSInt Val = Source.toAPSInt();
2983 if (Val.isNegative() || Val.getActiveBits() > 63)
2990template <PrimType Name, class T = typename PrimConv<Name>::T>
2992 const llvm::fltSemantics *Sem, uint32_t FPOI) {
2996 if (!From.isNumber())
3000 APSInt FromAP = From.toAPSInt();
3011template <PrimType Name, class T = typename PrimConv<Name>::T>
3015 if constexpr (std::is_same_v<T, Boolean>) {
3024 if ((Status & APFloat::opStatus::opInvalidOp)) {
3045 if (Ptr.isOpaquePointer()) {
3059 const Pointer &Ptr,
unsigned BitWidth);
3064template <PrimType Name, class T = typename PrimConv<Name>::T>
3070 if constexpr (std::is_same_v<T, Boolean>) {
3071 S.
Stk.
push<
T>(T::from(Ptr.getIntegerRepresentation()));
3073 if (Ptr.isBlockPointer()) {
3075 }
else if (Ptr.isOpaquePointer()) {
3076 if (
const Expr *BaseExpr = Ptr.asOpaquePointer().getBaseExpr()) {
3083 Ptr.asOpaquePointer().
Base.asVarDecl(), 0);
3086 }
else if (Ptr.isFunctionPointer()) {
3087 const void *FuncDecl = Ptr.asFunctionPointer().Func->getDecl();
3089 }
else if (Ptr.isStringPointer()) {
3091 (
const void *)Ptr.asStringPointer().getLiteral(), 0);
3093 S.
Stk.
push<
T>(T::from(Ptr.getIntegerRepresentation()));
3096 S.
Stk.
push<
T>(T::from(Ptr.getIntegerRepresentation()));
3101template <PrimType Name, class T = typename PrimConv<Name>::T>
3135 const llvm::fltSemantics *Sem) {
3138 Result.copy(Fixed.toFloat(Sem));
3143template <PrimType Name, class T = typename PrimConv<Name>::T>
3148 APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow);
3159 S.
CCEDiag(E, diag::note_constexpr_invalid_cast)
3160 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
3165bool PtrPtrCast(InterpState &S, CodePtr OpPC,
bool SrcIsVoidPtr,
3166 const Type *TargetType);
3172template <PrimType Name, class T = typename PrimConv<Name>::T>
3180 if (!
Result.singleWord())
3181 std::memset(
Result.Memory, 0,
Result.numWords() *
sizeof(uint64_t));
3188 if (!
Result.singleWord())
3189 std::memset(
Result.Memory, 0,
Result.numWords() *
sizeof(uint64_t));
3194template <PrimType Name, class T = typename PrimConv<Name>::T>
3198 if constexpr (std::is_same_v<T, Pointer>)
3215template <PrimType Name, class T = typename PrimConv<Name>::T>
3217 const auto &P = S.
Stk.
pop<
T>();
3237 if (!
This.isDummy()) {
3239 if (!
This.isTypeidPointer()) {
3240 [[maybe_unused]]
const Record *R =
This.getRecord();
3242 R =
This.narrow().getRecord();
3245 assert(R->getDecl() ==
3267template <
class LT,
class RT, ShiftDir Dir>
3271 const unsigned Bits = LHS.bitWidth();
3275 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
3276 RHS.bitWidth(), &RHS);
3278 if (RHS.isNegative()) {
3282 S.
CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
3286 RHS = RHS.isMin() ? RT(APSInt::getMaxValue(RHS.bitWidth(),
false)) : -RHS;
3290 S, OpPC, LHS, RHS,
Result);
3302 typename LT::AsUnsigned R;
3303 unsigned MaxShiftAmount = LHS.bitWidth() - 1;
3305 if (
Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
3307 if (LHS.isNegative())
3308 R = LT::AsUnsigned::zero(LHS.bitWidth());
3310 RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth());
3311 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
3312 LT::AsUnsigned::from(RHS,
Bits),
Bits, &R);
3314 }
else if (LHS.isNegative()) {
3316 R = LT::AsUnsigned::zero(LHS.bitWidth());
3319 typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS);
3320 LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS,
Bits),
Bits,
3326 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
3327 LT::AsUnsigned::from(RHS,
Bits),
Bits, &R);
3334 if (
Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
3336 R = LT::AsUnsigned::from(0);
3340 LT::shiftRight(LHS, LT::from(RHS,
Bits),
Bits, &A);
3341 R = LT::AsUnsigned::from(A);
3349template <
class LT,
class RT, ShiftDir Dir>
3352 const unsigned Bits = LHS.getBitWidth();
3357 APSInt(llvm::APInt(RHS.getBitWidth(),
static_cast<uint64_t
>(
Bits - 1)),
3360 if (RHS.isNegative()) {
3364 S.
CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS;
3369 S, OpPC, LHS, -(RHS.extend(RHS.getBitWidth() + 1)),
Result);
3393template <PrimType NameL, PrimType NameR>
3397 auto RHS = S.
Stk.
pop<RT>();
3405 RHS.toAPSInt(), &
Result);
3412template <PrimType NameL, PrimType NameR>
3416 auto RHS = S.
Stk.
pop<RT>();
3424 RHS.toAPSInt(), &
Result);
3434 llvm::FixedPointSemantics LHSSema = LHS.
getSemantics();
3436 unsigned ShiftBitWidth =
3437 LHSSema.getWidth() - (
unsigned)LHSSema.hasUnsignedPadding() - 1;
3442 if (RHS.isNegative()) {
3445 }
else if (
static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(
3446 ShiftBitWidth)) != RHS.toAPSInt()) {
3448 S.
CCEDiag(E, diag::note_constexpr_large_shift)
3449 << RHS.toAPSInt() << E->
getType() << ShiftBitWidth;
3472 S.
FFDiag(EndLoc, diag::note_constexpr_no_return);
3488 if (Ptr.isBlockPointer())
3496template <
typename T>
3499 if (Ptr.isOpaquePointer()) {
3507 if (Offset.isZero()) {
3508 if (
const Descriptor *Desc = Ptr.getFieldDesc();
3509 Desc && Desc->isArray() && Ptr.getIndex() == 0) {
3517 assert(!Offset.isZero());
3519 if (std::optional<Pointer>
Result =
3535template <PrimType Name, class T = typename PrimConv<Name>::T>
3543template <PrimType Name, class T = typename PrimConv<Name>::T>
3551template <PrimType Name, class T = typename PrimConv<Name>::T>
3558 assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
3563template <PrimType Name, class T = typename PrimConv<Name>::T>
3570 assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
3575template <PrimType Name, class T = typename PrimConv<Name>::T>
3577 uint32_t DestIndex, uint32_t Size) {
3581 if (SrcPtr.isDummy() || DestPtr.
isDummy())
3587 const Descriptor *SrcDesc = SrcPtr.getFieldDesc();
3593 for (uint32_t I = 0; I != Size; ++I) {
3599 DestPtr.
elem<
T>(DestIndex + I) = SrcPtr.elem<
T>(SrcIndex + I);
3615 if (!Ptr.isZeroSizeArray()) {
3621 if (Ptr.isBlockPointer()) {
3626 if (Ptr.isStringPointer()) {
3631 if (!Ptr.isOpaquePointer()) {
3644 diag::note_constexpr_unsupported_unsized_array);
3650 APSInt(APInt::getZero(1),
true),
3655 diag::note_constexpr_unsupported_unsized_array);
3665template <PrimType Name, class T = typename PrimConv<Name>::T>
3670 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
3675 if (IntVal.getOffset() != 0)
3681 if (IntVal.getOffset() != 0)
3684 const Block *B = (
const Block *)IntVal.getPtr();
3691 uint64_t NullValue =
3694 static_cast<uint64_t
>(IntVal) == NullValue);
3718 S.
FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)
3822 diag::note_constexpr_access_volatile_type)
3834 S.
CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
3842 diag::note_constexpr_pseudo_destructor);
3854 S.
CCEDiag(Loc, diag::note_constexpr_assumption_failed);
3858template <PrimType Name, class T = typename PrimConv<Name>::T>
3862 ArrayIndices.emplace_back(
3874template <PrimType Name, class T = typename PrimConv<Name>::T>
3881 S.
CCEDiag(Loc, diag::note_non_null_attribute_failed);
3887 const APSInt &
Value);
3889template <PrimType Name, class T = typename PrimConv<Name>::T>
3907 const FromT &OldPtr = S.
Stk.
pop<FromT>();
3909 if constexpr (std::is_same_v<FromT, FunctionPointer> &&
3910 std::is_same_v<ToT, Pointer>) {
3913 }
else if constexpr (std::is_same_v<FromT, Pointer> &&
3914 std::is_same_v<ToT, FunctionPointer>) {
3915 if (OldPtr.isFunctionPointer()) {
3917 OldPtr.getByteOffset());
3922 S.
Stk.
push<ToT>(ToT(OldPtr.getIntegerRepresentation(),
nullptr));
3952 if (!Ptr.isUnknownSizeArray() && NumElems > Ptr.getNumElems()) {
3954 << Ptr.getNumElems() << NumElems;
3975template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
3990 if (NumElements.isNegative()) {
4000 if (!
CheckArraySize(S, OpPC,
static_cast<uint64_t
>(NumElements)))
4004 Block *B = Allocator.
allocate(Source,
T,
static_cast<size_t>(NumElements),
4007 if (NumElements.isZero())
4014template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
4034 if (NumElements.isNegative()) {
4044 if (!
CheckArraySize(S, OpPC,
static_cast<uint64_t
>(NumElements)))
4048 Block *B = Allocator.
allocate(ElementDesc,
static_cast<size_t>(NumElements),
4051 if (NumElements.isZero())
4059bool Free(InterpState &S, CodePtr OpPC,
bool DeleteIsArrayForm,
4060 bool IsGlobalDelete);
4074 std::optional<uint64_t> ArraySize = std::nullopt);
4076template <PrimType Name, class T = typename PrimConv<Name>::T>
4078 const auto &Size = S.
Stk.
pop<
T>();
4083template <PrimType Name, class T = typename PrimConv<Name>::T>
4085 uint32_t ResultBitWidth,
const llvm::fltSemantics *Sem,
4086 const Type *TargetType) {
4092 if constexpr (std::is_same_v<T, Pointer>) {
4095 diag::note_constexpr_bit_cast_invalid_type)
4096 <<
true <<
false << 1 ;
4102 }
else if constexpr (std::is_same_v<T, MemberPointer>) {
4104 diag::note_constexpr_bit_cast_invalid_type)
4105 <<
true <<
false << 2 ;
4109 size_t BuffSize = ResultBitWidth / 8;
4111 bool HasIndeterminateBits =
false;
4113 Bits FullBitWidth(ResultBitWidth);
4114 Bits BitWidth = FullBitWidth;
4116 if constexpr (std::is_same_v<T, Floating>) {
4118 BitWidth =
Bits(llvm::APFloatBase::getSizeInBits(*Sem));
4121 if (!
DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,
4122 HasIndeterminateBits))
4125 if (!
CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
4128 if constexpr (std::is_same_v<T, Floating>) {
4135 T::bitcastFromMemory(Buff.data(), ResultBitWidth, &
Result);
4137 }
else if constexpr (std::is_same_v<T, Boolean>) {
4141 auto Val =
static_cast<unsigned int>(Buff[0]);
4144 diag::note_constexpr_bit_cast_unrepresentable_value)
4148 S.
Stk.
push<
T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
4151 S.
Stk.
push<
T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
4181bool DiagTypeid(InterpState &S, CodePtr OpPC);
4198 if constexpr (std::is_pointer<T>::value)
4201 return OpPC.
read<
T>();
4210 OpPC +=
align(F.bytesToSerialize());
4219 assert(
Result.bitWidth() == BitWidth);
4231 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.
uint64_t getTargetNullPointerValue(QualType QT) const
Get target-dependent integer value for null pointer which is used for constant folding.
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
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.
AddrLabelExpr - The GNU address of label extension, representing &&label.
LabelDecl * getLabel() const
Represents a C++ constructor within a class.
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.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
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)
SourceLocation getLocation(CodePtr PC) const
bool isLocalEnabled(unsigned Idx) const
void setParam(unsigned Index, const T &Value)
Mutates a local copy of a parameter.
SourceInfo getSource(CodePtr PC) const
Map a location to a source.
SourceRange getRange(CodePtr PC) const
void enableLocal(unsigned Idx)
Block * getLocalBlock(unsigned Offset) 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.
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 Expr * getExpr(CodePtr PC) const
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
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.
bool pointsToLabel() const
Whether this points to a block created for an AddrLabelExpr.
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.
bool isOpaquePointer() const
bool isStringPointer() const
T & deref() const
Dereferences the pointer, if it's live.
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
QualType getType() const
Returns the type of the innermost field.
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.
static bool elemsOfSameArray(const Pointer &A, const Pointer &B)
Checks if two pointers can be subtracted.
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.
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
bool isOnePastEnd() const
Checks if the index is one past end.
uint64_t getIntegerRepresentation() const
bool isBlockPointer() 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 isBaseClass() const
Checks if a structure is a base class.
static std::optional< std::pair< PtrView, PtrView > > computeSplitPoint(const Pointer &A, const Pointer &B)
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.
Structure/Class descriptor.
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)
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if a field from which a pointer is going to be derived is valid.
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 PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr, const Type *TargetType)
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 CastAPToOffsetIndex(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.
bool GetPtrParam(InterpState &S, uint32_t Index)
bool arrayElemPtrOpaque(InterpState &S, CodePtr OpPC, const Pointer &Ptr, APSInt &&Index, bool AllowReplace)
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)
std::optional< Pointer > addSubOffsetOpaque(InterpState &S, CodePtr OpPC, const Pointer &Ptr, APSInt &&Offset, ArithOp Op)
bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue)
Floating ReadArg< Floating >(InterpState &S, CodePtr &OpPC)
bool GetPtrLocal(InterpState &S, uint32_t I)
bool CastAddressSpace(InterpState &S, CodePtr OpPC, uint64_t Value, const Type *Ty)
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 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 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 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
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 LoadPopL(InterpState &S, CodePtr OpPC)
Like LoadPop above, but if any of the checks fail, we turn the pointer into an opaque pointer of appr...
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 GetStringPtr(InterpState &S, const Expr *Base)
bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off, bool NullOK, const Type *TargetType)
bool DiagTypeid(InterpState &S, CodePtr OpPC)
bool diagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
This is not used by any of the opcodes directly.
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK, bool WillBeActivated)
Checks if a value can be stored in a block.
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 virtBaseHelper(InterpState &S, const CXXRecordDecl *Decl, const Pointer &Ptr)
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.
@ ExprAddress
A pointer to an Expr.
@ 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 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)
bool arrayElemPtr(InterpState &S, CodePtr OpPC, const Pointer &Ptr, const T &Offset)
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 diagnoseArrayIndex(InterpState &S, CodePtr OpPC, const APSInt &Index, std::optional< uint64_t > NumElems, bool IsArray)
bool AddrOf(InterpState &S, CodePtr OpPC)
bool InitThisBitField(InterpState &S, CodePtr OpPC, uint32_t FieldOffset, uint32_t FieldBitWidth)
bool GetOpaquePtr(InterpState &S, DeclOrExpr DOE, bool ConstexprUnknown)
bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC)
static bool Activate(InterpState &S)
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 CheckFloatStatus(InterpState &S, CodePtr OpPC, APFloat::opStatus Status, FPOptions FPO)
Check if the given floating-point evaluation status is allowed for compile-time constant folding duri...
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 GetPtrVirtBasePop(InterpState &S, CodePtr OpPC, const CXXRecordDecl *D)
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 DefaultInit(InterpState &S, CodePtr OpPC, const CXXConstructorDecl *Ctor)
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 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 GetPtrVirtBase(InterpState &S, CodePtr OpPC, const CXXRecordDecl *D)
bool IsBaseClass(InterpState &S)
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 CheckLoad(InterpState &S, CodePtr OpPC, PtrView Ptr, AccessKinds AK)
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 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 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 TrivialCopy(InterpState &S, CodePtr OpPC, bool Activate, const Function *Func)
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 StartFieldInit(InterpState &S, uint32_t FieldOffset)
bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool GetMemberPtr(InterpState &S, const ValueDecl *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 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 GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const CXXRecordDecl *D)
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)
Top level wrappers for InstallAPI frontend operations.
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
const FunctionProtoType * T
@ Off
Never emit colors regardless of the output stream.
@ ConstantFold
Fold the expression to a constant.
U cast(CodeGen::Address addr)
__UINTPTR_TYPE__ uintptr_t
An unsigned integer type with the property that any valid pointer to void can be converted to this ty...
__builtin_elementwise_add_sat __builtin_elementwise_sub_sat uint32_t __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
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.
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.
bool isArray() const
Checks if the descriptor is of an array.
Descriptor used for global variables.
OpaquePointer withFieldType(const Type *FieldTy, std::optional< bool > PastEnd=std::nullopt) const
llvm::PointerIntPair< const Type *, 2, unsigned > FieldType
const PointerPathEntry * Path
QualType getFieldType() const
bool isOnePastEnd() const
bool isUnknownSizeArray() const
OpaquePointer withPath(const PointerPathEntry *Path, unsigned PathLength, const Type *FieldTy, std::optional< bool > PastEnd=std::nullopt) const
Mapping from primitive types to their representation.
PtrView atField(unsigned Offset) const
PtrView atIndex(unsigned Idx) const