13#ifndef LLVM_CLANG_AST_INTERP_INTERP_H
14#define LLVM_CLANG_AST_INTERP_INTERP_H
36#include "llvm/ADT/APFloat.h"
37#include "llvm/ADT/APSInt.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;
80 std::optional<uint64_t> NumElems = std::nullopt,
111 uint32_t VarArgSize);
113 uint32_t VarArgSize);
115 uint32_t VarArgSize);
123 bool TargetIsUCharOrByte);
139 bool IsReferenceCast);
156 const APSInt *
Value =
nullptr,
160template <ShiftDir Dir,
typename LT,
typename RT>
163 if (RHS.isNegative()) {
178 if (LHS.isSigned() && !S.
getLangOpts().CPlusPlus20) {
181 if (LHS.isNegative()) {
186 }
else if (LHS.toUnsigned().countLeadingZeros() <
187 static_cast<unsigned>(RHS)) {
205 if (!LHS.isNumber() || !RHS.isNumber())
211 if constexpr (std::is_same_v<T, Floating>) {
212 S.
CCEDiag(Op, diag::note_expr_divide_by_zero)
213 << Op->getRHS()->getSourceRange();
217 S.
FFDiag(Op, diag::note_expr_divide_by_zero)
218 << Op->getRHS()->getSourceRange();
222 if constexpr (!std::is_same_v<T, FixedPoint>) {
223 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
224 APSInt LHSInt = LHS.toAPSInt();
226 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
229 S.
CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->
getType();
250 APFloat::opStatus Status,
FPOptions FPO);
255bool CheckFloatStatus(InterpState &S, CodePtr OpPC, APFloat::opStatus Status,
277template <PrimType Name, class T = typename PrimConv<Name>::T>
316 template <typename U>
class OpAP>
321 assert(LHS.isNumber() && RHS.isNumber());
337 if constexpr (std::is_same_v<T, FixedPoint>)
353 .toString(Trunc, 10,
Result.isSigned(),
false,
367template <
typename T,
template <
typename U>
class Op>
369 assert(!LHS.isNumber() || !RHS.isNumber());
373 typename T::ReprT Offset;
375 if (LHS.isNumber()) {
379 Number =
static_cast<typename T::ReprT
>(LHS);
381 Offset = RHS.getOffset();
382 Kind = RHS.getKind();
384 assert(RHS.isNumber());
388 Number =
static_cast<typename T::ReprT
>(RHS);
390 Offset = LHS.getOffset();
391 Kind = LHS.getKind();
398template <PrimType Name, class T = typename PrimConv<Name>::T>
402 const unsigned Bits = RHS.bitWidth() + 1;
405 if (LHS.isNumber() != RHS.isNumber())
407 else if (LHS.isNumber() && RHS.isNumber())
427template <PrimType Name, class T = typename PrimConv<Name>::T>
431 const unsigned Bits = RHS.bitWidth() + 1;
440 ?
reinterpret_cast<const Expr *
>(LHS.getPtr())
443 ?
reinterpret_cast<const Expr *
>(RHS.getPtr())
445 if (!isa_and_nonnull<AddrLabelExpr>(A) ||
446 !isa_and_nonnull<AddrLabelExpr>(B))
451 if (LHSAddrExpr->getLabel()->getDeclContext() !=
452 RHSAddrExpr->getLabel()->getDeclContext())
455 S.
Stk.
push<
T>(LHSAddrExpr, RHSAddrExpr);
459 if (!LHS.isNumber() && RHS.isNumber())
461 else if (LHS.isNumber() && RHS.isNumber())
481template <PrimType Name, class T = typename PrimConv<Name>::T>
485 const unsigned Bits = RHS.bitWidth() * 2;
488 if (!LHS.isNumber() || !RHS.isNumber())
508template <PrimType Name, class T = typename PrimConv<Name>::T>
514 if constexpr (std::is_same_v<T, Floating>) {
520 APFloat ResR(A.getSemantics());
521 APFloat ResI(A.getSemantics());
532 Result.initializeAllElements();
535 const T &LHSR = LHS.elem<
T>(0);
536 const T &LHSI = LHS.elem<
T>(1);
537 const T &RHSR = RHS.
elem<
T>(0);
538 const T &RHSI = RHS.
elem<
T>(1);
539 unsigned Bits = LHSR.bitWidth();
542 if (!LHSR.isNumber() || !LHSI.isNumber() || !RHSR.isNumber() ||
550 if (T::mul(LHSR, RHSR,
Bits, &A))
556 if (T::mul(LHSI, RHSI,
Bits, &B))
565 if (T::mul(LHSR, RHSI,
Bits, &A))
567 if (T::mul(LHSI, RHSR,
Bits, &B))
575 Result.initializeAllElements();
581template <PrimType Name, class T = typename PrimConv<Name>::T>
587 if constexpr (std::is_same_v<T, Floating>) {
593 APFloat ResR(A.getSemantics());
594 APFloat ResI(A.getSemantics());
606 Result.initializeAllElements();
609 const T &LHSR = LHS.elem<
T>(0);
610 const T &LHSI = LHS.elem<
T>(1);
611 const T &RHSR = RHS.
elem<
T>(0);
612 const T &RHSI = RHS.
elem<
T>(1);
613 unsigned Bits = LHSR.bitWidth();
615 if (RHSR.isZero() && RHSI.isZero()) {
617 S.
FFDiag(E, diag::note_expr_divide_by_zero);
628 if (T::mul(RHSR, RHSR,
Bits, &A) || T::mul(RHSI, RHSI,
Bits, &B)) {
635 if (T::add(A, B,
Bits, &Den))
640 S.
FFDiag(E, diag::note_expr_divide_by_zero);
651 if (T::mul(LHSR, RHSR,
Bits, &A) || T::mul(LHSI, RHSI,
Bits, &B))
653 if (T::add(A, B,
Bits, &ResultR))
655 if (T::div(ResultR, Den,
Bits, &ResultR))
659 if (T::mul(LHSI, RHSR,
Bits, &A) || T::mul(LHSR, RHSI,
Bits, &B))
661 if (T::sub(A, B,
Bits, &ResultI))
663 if (T::div(ResultI, Den,
Bits, &ResultI))
665 Result.initializeAllElements();
674template <PrimType Name, class T = typename PrimConv<Name>::T>
678 unsigned Bits = RHS.bitWidth();
681 if (!LHS.isNumber() || !RHS.isNumber())
699template <PrimType Name, class T = typename PrimConv<Name>::T>
703 unsigned Bits = RHS.bitWidth();
706 if (!LHS.isNumber() || !RHS.isNumber())
724template <PrimType Name, class T = typename PrimConv<Name>::T>
728 unsigned Bits = RHS.bitWidth();
731 if (!LHS.isNumber() || !RHS.isNumber())
749template <PrimType Name, class T = typename PrimConv<Name>::T>
753 const unsigned Bits = RHS.bitWidth() * 2;
772template <PrimType Name, class T = typename PrimConv<Name>::T>
776 const unsigned Bits = RHS.bitWidth() * 2;
790 if constexpr (std::is_same_v<T, FixedPoint>) {
829template <PrimType Name, class T = typename PrimConv<Name>::T>
833 if constexpr (std::is_same_v<T, Floating>) {
852 "don't expect other types to fail at constexpr negation");
863 NegatedValue.trunc(
Result.bitWidth())
864 .toString(Trunc, 10,
Result.isSigned(),
false,
884template <
typename T, IncDecOp Op, PushVal DoPush>
887 assert(!Ptr.isDummy());
894 if constexpr (std::is_same_v<T, Boolean>) {
899 const T &
Value = Ptr.deref<
T>();
903 if (!
Value.isNumber())
915 if (!T::increment(
Value, &
Result) || !CanOverflow) {
917 Ptr.deref<
T>() =
Result.truncate(*BitWidth);
923 if (!T::decrement(
Value, &
Result) || !CanOverflow) {
925 Ptr.deref<
T>() =
Result.truncate(*BitWidth);
952 APResult.trunc(
Result.bitWidth())
953 .toString(Trunc, 10,
Result.isSigned(),
false,
966template <PrimType Name, class T = typename PrimConv<Name>::T>
978template <PrimType Name, class T = typename PrimConv<Name>::T>
994template <PrimType Name, class T = typename PrimConv<Name>::T>
1005template <PrimType Name, class T = typename PrimConv<Name>::T>
1007 uint32_t BitWidth) {
1018template <PrimType Name, class T = typename PrimConv<Name>::T>
1029template <PrimType Name, class T = typename PrimConv<Name>::T>
1031 uint32_t BitWidth) {
1046template <PrimType Name, class T = typename PrimConv<Name>::T>
1057template <PrimType Name, class T = typename PrimConv<Name>::T>
1059 uint32_t BitWidth) {
1073template <PrimType Name, class T = typename PrimConv<Name>::T>
1084template <PrimType Name, class T = typename PrimConv<Name>::T>
1086 uint32_t BitWidth) {
1097template <PrimType Name, class T = typename PrimConv<Name>::T>
1107template <PrimType Name, class T = typename PrimConv<Name>::T>
1109 uint32_t BitWidth) {
1119template <IncDecOp Op, PushVal DoPush>
1129 llvm::APFloat::opStatus Status;
1182template <PrimType Name, class T = typename PrimConv<Name>::T>
1190 if (!T::comp(Val, &
Result)) {
1203template <
typename T>
1205 assert((!std::is_same_v<T, MemberPointer>) &&
1206 "Non-equality comparisons on member pointer types should already be "
1207 "rejected in Sema.");
1213 if (!LHS.isNumber() || !RHS.isNumber())
1217 S.
Stk.
push<BoolT>(BoolT::from(
Fn(LHS.compare(RHS))));
1221template <
typename T>
1236 S.
FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1249 S.
FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1257 if (std::optional<std::pair<PtrView, PtrView>> Split =
1259 const FieldDecl *LF = Split->first.getField();
1260 const FieldDecl *RF = Split->second.getField();
1263 diag::note_constexpr_pointer_comparison_base_classes);
1266 diag::note_constexpr_pointer_comparison_base_field)
1267 << Split->first.getRecord()->getDecl() << RF->
getParent() << RF;
1270 diag::note_constexpr_pointer_comparison_base_field)
1271 << Split->second.getRecord()->getDecl() << LF->
getParent() << LF;
1275 diag::note_constexpr_pointer_comparison_differing_access)
1290 return (
Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
1291 Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
1292 Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||
1293 Builtin == Builtin::BI__builtin_function_start);
1305 if (LHS.isZero() && RHS.
isZero()) {
1311 for (
const auto &P : {LHS, RHS}) {
1316 S.
FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
1323 if (RHS.
isZero() || LHS.isZero()) {
1328 assert(!LHS.isZero());
1343 std::optional<size_t> A = LHS.computeOffsetForComparison(S.
getASTContext());
1356 diag::note_constexpr_literal_comparison)
1364 S.
FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
1370 S.
FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
1376 for (
const auto &P : {LHS, RHS}) {
1379 if (P.pointsToLiteral()) {
1380 const Expr *E = P.getRootExpr();
1383 S.
FFDiag(Loc, diag::note_constexpr_literal_comparison);
1386 if (
const auto *CE = dyn_cast<CallExpr>(E);
1389 S.
FFDiag(Loc, diag::note_constexpr_opaque_call_comparison)
1393 }
else if (P.isIntegralPointer()) {
1395 S.
FFDiag(Loc, diag::note_constexpr_pointer_constant_comparison)
1404 S.
FFDiag(Loc, diag::note_constexpr_pointer_comparison_zero_sized)
1413 diag::note_constexpr_pointer_comparison_unspecified)
1431 for (
const auto &MP : {LHS, RHS}) {
1434 S.
FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison)
1435 << MP.getMemberFunction();
1443 if (LHS.
isZero() && RHS.isZero()) {
1447 if (LHS.
isZero() || RHS.isZero()) {
1453 for (
const auto &MP : {LHS, RHS}) {
1457 S.
CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
1465template <PrimType Name, class T = typename PrimConv<Name>::T>
1472template <PrimType Name, class T = typename PrimConv<Name>::T>
1479 if constexpr (std::is_same_v<T, Pointer>) {
1482 diag::note_constexpr_pointer_comparison_unspecified)
1487 std::optional<size_t> LHSOffset =
1489 std::optional<size_t> RHSOffset =
1491 if (!LHSOffset || !RHSOffset)
1494 if (LHSOffset < RHSOffset)
1496 else if (LHSOffset > RHSOffset)
1501 CmpResult = LHS.compare(RHS);
1505 const auto *CmpValueInfo =
1507 assert(CmpValueInfo);
1508 assert(CmpValueInfo->hasValidIntValue());
1512template <PrimType Name, class T = typename PrimConv<Name>::T>
1519template <PrimType Name, class T = typename PrimConv<Name>::T>
1526template <PrimType Name, class T = typename PrimConv<Name>::T>
1534template <PrimType Name, class T = typename PrimConv<Name>::T>
1541template <PrimType Name, class T = typename PrimConv<Name>::T>
1553template <PrimType Name, class T = typename PrimConv<Name>::T>
1559template <PrimType Name, class T = typename PrimConv<Name>::T>
1570 const auto &Top = S.
Stk.
pop<TopT>();
1571 const auto &Bottom = S.
Stk.
pop<BottomT>();
1583template <PrimType Name, class T = typename PrimConv<Name>::T>
1587 Result.copy(Arg.toAPSInt());
1592 if constexpr (std::is_same_v<T, uint16_t>) {
1594 }
else if constexpr (std::is_same_v<T, int16_t>) {
1596 }
else if constexpr (std::is_same_v<T, uint32_t>) {
1598 }
else if constexpr (std::is_same_v<T, int32_t>) {
1600 }
else if constexpr (std::is_same_v<T, uint64_t>) {
1602 }
else if constexpr (std::is_same_v<T, int64_t>) {
1623template <PrimType Name, class T = typename PrimConv<Name>::T>
1633bool PseudoDtor(InterpState &S, CodePtr OpPC);
1642template <PrimType Name, class T = typename PrimConv<Name>::T>
1648template <PrimType Name, class T = typename PrimConv<Name>::T>
1657template <PrimType Name, class T = typename PrimConv<Name>::T>
1665template <PrimType Name, class T = typename PrimConv<Name>::T>
1691template <PrimType Name, class T = typename PrimConv<Name>::T>
1715template <PrimType Name, class T = typename PrimConv<Name>::T>
1723 if (!
This.isBlockPointer())
1733template <PrimType Name, class T = typename PrimConv<Name>::T>
1745template <PrimType Name, class T = typename PrimConv<Name>::T>
1756template <PrimType Name, class T = typename PrimConv<Name>::T>
1762template <PrimType Name, class T = typename PrimConv<Name>::T>
1768 if constexpr (std::is_same_v<T, Floating>) {
1770 if (!Val.singleWord()) {
1771 uint64_t *NewMemory =
new (S.
P) uint64_t[Val.numWords()];
1772 Val.take(NewMemory);
1775 }
else if constexpr (std::is_same_v<T, MemberPointer>) {
1779 for (
unsigned I = 0; I != PathLength; ++I) {
1780 NewPath[I] = Val.getPathEntry(I);
1782 Val.takePath(NewPath);
1783 }
else if constexpr (std::is_same_v<T, Pointer>) {
1785 if (Val.isOpaquePointer() && Val.asOpaquePointer().PathLength != 0) {
1792 Val.getByteOffset());
1796 auto &Val = P.
deref<
T>();
1797 if (!Val.singleWord()) {
1798 uint64_t *NewMemory =
new (S.
P) uint64_t[Val.numWords()];
1799 Val.take(NewMemory);
1810template <PrimType Name, class T = typename PrimConv<Name>::T>
1818 assert(Ptr.getRootExpr());
1840template <PrimType Name, class T = typename PrimConv<Name>::T>
1847 if (!
This.isDereferencable())
1851 assert(Field.canBeInitialized());
1857template <PrimType Name, class T = typename PrimConv<Name>::T>
1864 if (!
This.isDereferencable())
1868 assert(Field.canBeInitialized());
1875template <PrimType Name, class T = typename PrimConv<Name>::T>
1877 uint32_t FieldBitWidth) {
1883 if (!
This.isDereferencable())
1887 assert(Field.canBeInitialized());
1891 if (!
Value.isNumber())
1895 Field.deref<
T>() =
Value.truncate(FieldBitWidth);
1900template <PrimType Name, class T = typename PrimConv<Name>::T>
1902 uint32_t FieldOffset, uint32_t FieldBitWidth) {
1908 if (!
This.isDereferencable())
1912 assert(Field.canBeInitialized());
1916 if (!
Value.isNumber())
1920 Field.deref<
T>() =
Value.truncate(FieldBitWidth);
1929template <PrimType Name, class T = typename PrimConv<Name>::T>
1933 if (!Ptr.isDereferencable())
1941 const Pointer &Field = Ptr.atField(I);
1942 Field.deref<
T>() =
Value;
1947template <PrimType Name, class T = typename PrimConv<Name>::T>
1951 if (!Ptr.isDereferencable())
1958 const Pointer &Field = Ptr.atField(I);
1959 Field.deref<
T>() =
Value;
1965template <PrimType Name, class T = typename PrimConv<Name>::T>
1967 uint32_t FieldBitWidth) {
1970 if (!Ptr.isDereferencable())
1974 if (!
Value.isNumber())
1982 const Pointer &Field = Ptr.atField(FieldOffset);
1984 unsigned BitWidth = std::min(FieldBitWidth,
Value.bitWidth());
1987 if constexpr (T::isSigned())
1989 Value.toAPSInt().trunc(BitWidth).sextOrTrunc(
Value.bitWidth()));
1992 Value.toAPSInt().trunc(BitWidth).zextOrTrunc(
Value.bitWidth()));
1996 Field.deref<
T>() =
Value.truncate(FieldBitWidth);
2002template <PrimType Name, class T = typename PrimConv<Name>::T>
2004 uint32_t FieldBitWidth) {
2007 if (!Ptr.isDereferencable())
2011 if (!
Value.isNumber())
2019 const Pointer &Field = Ptr.atField(FieldOffset);
2021 unsigned BitWidth = std::min(FieldBitWidth,
Value.bitWidth());
2024 if constexpr (T::isSigned())
2026 Value.toAPSInt().trunc(BitWidth).sextOrTrunc(
Value.bitWidth()));
2029 Value.toAPSInt().trunc(BitWidth).zextOrTrunc(
Value.bitWidth()));
2033 Field.deref<
T>() =
Value.truncate(FieldBitWidth);
2101bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t
Off,
bool NullOK);
2104 const Type *TargetType,
const Type *FinalType);
2112 if (!
This.isBlockPointer())
2130 if (Ptr.canBeInitialized())
2137 if (Ptr.canBeInitialized())
2144 if (Ptr.canBeInitialized()) {
2153 if (Ptr.canBeInitialized()) {
2171 diag::note_constexpr_dereferencing_null);
2213template <PrimType Name, class T = typename PrimConv<Name>::T>
2218 if (!Ptr.canDeref(Name))
2224template <PrimType Name, class T = typename PrimConv<Name>::T>
2229 if (!Ptr.canDeref(Name))
2242 bool Failed =
false;
2245 if (!Ptr.isBlockPointer())
2247 if (!Failed && !Ptr.canDeref(
PT_Ptr))
2252 if (Ptr.isOpaquePointer()) {
2255 if (!Ptr.asOpaquePointer().Base.getType()->isPointerType())
2260 Ptr.getByteOffset());
2265 if (!Ptr.isBlockPointer())
2275template <PrimType Name, class T = typename PrimConv<Name>::T>
2281 if (!Ptr.canDeref(Name))
2283 if (Ptr.canBeInitialized())
2289template <PrimType Name, class T = typename PrimConv<Name>::T>
2295 if (!Ptr.canDeref(Name))
2297 if (Ptr.canBeInitialized())
2305 if (Ptr.canBeInitialized())
2317 assert(Ptr.atField(I).canBeInitialized());
2318 Ptr.atField(I).activate();
2322template <PrimType Name, class T = typename PrimConv<Name>::T>
2329 if (Ptr.canBeInitialized()) {
2337template <PrimType Name, class T = typename PrimConv<Name>::T>
2344 if (Ptr.canBeInitialized()) {
2352template <PrimType Name, class T = typename PrimConv<Name>::T>
2359 if (Ptr.canBeInitialized())
2361 if (
const auto *FD = Ptr.getField())
2362 Ptr.deref<
T>() =
Value.truncate(FD->getBitWidthValue());
2368template <PrimType Name, class T = typename PrimConv<Name>::T>
2374 if (Ptr.canBeInitialized())
2376 if (
const auto *FD = Ptr.getField())
2377 Ptr.deref<
T>() =
Value.truncate(FD->getBitWidthValue());
2383template <PrimType Name, class T = typename PrimConv<Name>::T>
2390 if (Ptr.canBeInitialized()) {
2394 if (
const auto *FD = Ptr.getField())
2395 Ptr.deref<
T>() =
Value.truncate(FD->getBitWidthValue());
2401template <PrimType Name, class T = typename PrimConv<Name>::T>
2408 if (Ptr.canBeInitialized()) {
2412 if (
const auto *FD = Ptr.getField())
2413 Ptr.deref<
T>() =
Value.truncate(FD->getBitWidthValue());
2419template <PrimType Name, class T = typename PrimConv<Name>::T>
2426 new (&Ptr.deref<
T>())
T(
Value);
2430template <PrimType Name, class T = typename PrimConv<Name>::T>
2437 new (&Ptr.deref<
T>())
T(
Value);
2444template <PrimType Name, class T = typename PrimConv<Name>::T>
2449 if (Ptr.isConstexprUnknown())
2458 if (Idx == 0 && !Desc->
isArray()) {
2460 new (&Ptr.deref<
T>())
T(
Value);
2470 S.
FFDiag(Loc, diag::note_constexpr_access_past_end)
2475 Ptr.initializeElement(Idx);
2476 new (&Ptr.elem<
T>(Idx))
T(
Value);
2481template <PrimType Name, class T = typename PrimConv<Name>::T>
2486 if (Ptr.isConstexprUnknown())
2495 if (Idx == 0 && !Desc->
isArray()) {
2497 new (&Ptr.deref<
T>())
T(
Value);
2507 S.
FFDiag(Loc, diag::note_constexpr_access_past_end)
2512 Ptr.initializeElement(Idx);
2513 new (&Ptr.elem<
T>(Idx))
T(
Value);
2528 if (std::optional<Pointer> Ptr = MP.toPointer(S.
Ctx)) {
2535bool Memcpy(InterpState &S, CodePtr OpPC);
2543template <
class T, ArithOp Op>
2545 const T &Offset,
const Pointer &Ptr,
2546 bool IsPointerArith =
false) {
2548 if (Offset.isZero())
2555 return std::nullopt;
2560 return std::nullopt;
2563 if (Ptr.isIntegralPointer()) {
2564 uint64_t
V = Ptr.getIntegerRepresentation();
2565 QualType ElemType = Ptr.asIntPointer().getPointeeType();
2570 uint64_t O =
static_cast<uint64_t
>(Offset) * ElemSize;
2572 return Pointer(
V + O, Ptr.asIntPointer().getType());
2574 return Pointer(
V - O, Ptr.asIntPointer().getType());
2575 }
else if (Ptr.isFunctionPointer()) {
2576 uint64_t O =
static_cast<uint64_t
>(Offset);
2579 N = Ptr.getByteOffset() + O;
2581 N = Ptr.getByteOffset() - O;
2585 return Pointer(Ptr.asFunctionPointer().Func, N);
2586 }
else if (Ptr.isStringPointer()) {
2589 NewOffset = Ptr.getByteOffset() +
static_cast<int64_t
>(Offset);
2591 NewOffset = Ptr.getByteOffset() -
static_cast<int64_t
>(Offset);
2592 if (NewOffset < 0 ||
2593 NewOffset > (Ptr.asStringPointer().getLiteral()->getLength() + 1)) {
2595 (Ptr.asStringPointer().getLiteral()->getLength() + 1));
2596 return std::nullopt;
2598 return Pointer(Ptr.asStringPointer(), NewOffset);
2599 }
else if (!Ptr.isBlockPointer()) {
2600 return std::nullopt;
2603 assert(Ptr.isBlockPointer());
2605 uint64_t MaxIndex =
static_cast<uint64_t
>(Ptr.getNumElems());
2607 if (Ptr.isOnePastEnd())
2610 Index = Ptr.getIndex();
2614 auto DiagInvalidOffset = [&]() ->
void {
2615 const unsigned Bits = Offset.bitWidth();
2616 APSInt APOffset(Offset.toAPSInt().extend(
Bits + 2),
false);
2620 (Op ==
ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
2625 uint64_t IOffset =
static_cast<uint64_t
>(Offset);
2626 uint64_t MaxOffset = MaxIndex - Index;
2630 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
2631 DiagInvalidOffset();
2634 if (Offset.isPositive() && IOffset > MaxOffset)
2635 DiagInvalidOffset();
2638 if (Offset.isPositive() && Index < IOffset)
2639 DiagInvalidOffset();
2642 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
2643 DiagInvalidOffset();
2647 return std::nullopt;
2650 int64_t WideIndex =
static_cast<int64_t
>(Index);
2651 int64_t WideOffset =
static_cast<int64_t
>(Offset);
2654 Result = WideIndex + WideOffset;
2656 Result = WideIndex - WideOffset;
2661 if (
Result == 0 && Ptr.isOnePastEnd()) {
2662 if (Ptr.getFieldDesc()->isArray())
2663 return Ptr.atIndex(0);
2664 return Pointer(Ptr.asBlockPointer().Pointee, Ptr.asBlockPointer().Base);
2667 return Ptr.atIndex(
static_cast<uint64_t
>(
Result));
2671 const Pointer &Ptr, APSInt &&Offset,
2673template <PrimType Name, class T = typename PrimConv<Name>::T>
2678 if (Ptr.isOpaquePointer()) {
2679 if (std::optional<Pointer>
Result =
2688 S, OpPC, Offset, Ptr,
true)) {
2695template <PrimType Name, class T = typename PrimConv<Name>::T>
2700 if (Ptr.isOpaquePointer()) {
2701 if (std::optional<Pointer>
Result =
2710 S, OpPC, Offset, Ptr,
true)) {
2718 bool ConstexprUnknown) {
2723template <ArithOp Op>
2726 if (!Ptr.isDereferencable())
2739 if (std::optional<Pointer>
Result =
2748 OneT One = OneT::from(1);
2749 if (std::optional<Pointer>
Result =
2761 if (!Ptr.isInitialized())
2770 if (!Ptr.isInitialized())
2779template <PrimType Name, class T = typename PrimConv<Name>::T>
2788 if (!LHSAddrExpr || !RHSAddrExpr) {
2790 diag::note_constexpr_pointer_arith_unspecified)
2800 S.
Stk.
push<
T>(LHSAddrExpr, RHSAddrExpr);
2809 diag::note_constexpr_pointer_arith_unspecified)
2815 if (ElemSize == 0) {
2820 diag::note_constexpr_pointer_subtraction_zero_size)
2837 diag::note_constexpr_pointer_subtraction_not_same_array);
2849 (
static_cast<int64_t
>(*VL) -
static_cast<int64_t
>(*VR)) / ElemSize;
2850 if (
static_cast<int64_t
>(T::from(R64)) != R64)
2896 if (!(U::bitWidth() >= 32 && U::bitWidth() <= In.bitWidth()))
2908 llvm::RoundingMode RM) {
2918 FixedPointSemantics::getFromOpaqueInt(FPS);
2933template <PrimType Name, class T = typename PrimConv<Name>::T>
2938 if (!Source.isNumber())
2945 APInt SourceInt = Source.toAPSInt().extOrTrunc(BitWidth);
2952template <PrimType Name, class T = typename PrimConv<Name>::T>
2957 if (!Source.isNumber())
2964 APInt SourceInt = Source.toAPSInt().extOrTrunc(BitWidth);
2974template <PrimType Name, class T = typename PrimConv<Name>::T>
2977 APSInt Val = Source.toAPSInt();
2978 if (Val.isNegative() || Val.getActiveBits() > 63)
2985template <PrimType Name, class T = typename PrimConv<Name>::T>
2987 const llvm::fltSemantics *Sem, uint32_t FPOI) {
2991 if (!From.isNumber())
2995 APSInt FromAP = From.toAPSInt();
3006template <PrimType Name, class T = typename PrimConv<Name>::T>
3010 if constexpr (std::is_same_v<T, Boolean>) {
3019 if ((Status & APFloat::opStatus::opInvalidOp)) {
3040 if (Ptr.isOpaquePointer()) {
3054 const Pointer &Ptr,
unsigned BitWidth);
3059template <PrimType Name, class T = typename PrimConv<Name>::T>
3065 if constexpr (std::is_same_v<T, Boolean>) {
3066 S.
Stk.
push<
T>(T::from(Ptr.getIntegerRepresentation()));
3068 if (Ptr.isBlockPointer()) {
3070 }
else if (Ptr.isOpaquePointer()) {
3071 if (
const Expr *BaseExpr = Ptr.asOpaquePointer().getBaseExpr()) {
3078 Ptr.asOpaquePointer().
Base.asVarDecl(), 0);
3081 }
else if (Ptr.isFunctionPointer()) {
3082 const void *FuncDecl = Ptr.asFunctionPointer().Func->getDecl();
3084 }
else if (Ptr.isStringPointer()) {
3086 (
const void *)Ptr.asStringPointer().getLiteral(), 0);
3088 S.
Stk.
push<
T>(T::from(Ptr.getIntegerRepresentation()));
3091 S.
Stk.
push<
T>(T::from(Ptr.getIntegerRepresentation()));
3096template <PrimType Name, class T = typename PrimConv<Name>::T>
3130 const llvm::fltSemantics *Sem) {
3133 Result.copy(Fixed.toFloat(Sem));
3138template <PrimType Name, class T = typename PrimConv<Name>::T>
3143 APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow);
3154 S.
CCEDiag(E, diag::note_constexpr_invalid_cast)
3155 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
3160bool PtrPtrCast(InterpState &S, CodePtr OpPC,
bool SrcIsVoidPtr,
3161 const Type *TargetType);
3167template <PrimType Name, class T = typename PrimConv<Name>::T>
3175 if (!
Result.singleWord())
3176 std::memset(
Result.Memory, 0,
Result.numWords() *
sizeof(uint64_t));
3183 if (!
Result.singleWord())
3184 std::memset(
Result.Memory, 0,
Result.numWords() *
sizeof(uint64_t));
3189template <PrimType Name, class T = typename PrimConv<Name>::T>
3193 if constexpr (std::is_same_v<T, Pointer>)
3210template <PrimType Name, class T = typename PrimConv<Name>::T>
3212 const auto &P = S.
Stk.
pop<
T>();
3232 if (!
This.isDummy()) {
3234 if (!
This.isTypeidPointer()) {
3235 [[maybe_unused]]
const Record *R =
This.getRecord();
3237 R =
This.narrow().getRecord();
3240 assert(R->getDecl() ==
3262template <
class LT,
class RT, ShiftDir Dir>
3266 const unsigned Bits = LHS.bitWidth();
3270 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
3271 RHS.bitWidth(), &RHS);
3273 if (RHS.isNegative()) {
3277 S.
CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
3281 RHS = RHS.isMin() ? RT(APSInt::getMaxValue(RHS.bitWidth(),
false)) : -RHS;
3285 S, OpPC, LHS, RHS,
Result);
3297 typename LT::AsUnsigned R;
3298 unsigned MaxShiftAmount = LHS.bitWidth() - 1;
3300 if (
Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
3302 if (LHS.isNegative())
3303 R = LT::AsUnsigned::zero(LHS.bitWidth());
3305 RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth());
3306 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
3307 LT::AsUnsigned::from(RHS,
Bits),
Bits, &R);
3309 }
else if (LHS.isNegative()) {
3311 R = LT::AsUnsigned::zero(LHS.bitWidth());
3314 typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS);
3315 LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS,
Bits),
Bits,
3321 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
3322 LT::AsUnsigned::from(RHS,
Bits),
Bits, &R);
3329 if (
Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
3331 R = LT::AsUnsigned::from(0);
3335 LT::shiftRight(LHS, LT::from(RHS,
Bits),
Bits, &A);
3336 R = LT::AsUnsigned::from(A);
3344template <
class LT,
class RT, ShiftDir Dir>
3347 const unsigned Bits = LHS.getBitWidth();
3352 APSInt(llvm::APInt(RHS.getBitWidth(),
static_cast<uint64_t
>(
Bits - 1)),
3355 if (RHS.isNegative()) {
3359 S.
CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS;
3364 S, OpPC, LHS, -(RHS.extend(RHS.getBitWidth() + 1)),
Result);
3388template <PrimType NameL, PrimType NameR>
3392 auto RHS = S.
Stk.
pop<RT>();
3400 RHS.toAPSInt(), &
Result);
3407template <PrimType NameL, PrimType NameR>
3411 auto RHS = S.
Stk.
pop<RT>();
3419 RHS.toAPSInt(), &
Result);
3429 llvm::FixedPointSemantics LHSSema = LHS.
getSemantics();
3431 unsigned ShiftBitWidth =
3432 LHSSema.getWidth() - (
unsigned)LHSSema.hasUnsignedPadding() - 1;
3437 if (RHS.isNegative()) {
3440 }
else if (
static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(
3441 ShiftBitWidth)) != RHS.toAPSInt()) {
3443 S.
CCEDiag(E, diag::note_constexpr_large_shift)
3444 << RHS.toAPSInt() << E->
getType() << ShiftBitWidth;
3467 S.
FFDiag(EndLoc, diag::note_constexpr_no_return);
3483 if (Ptr.isBlockPointer())
3491template <
typename T>
3494 if (Ptr.isOpaquePointer()) {
3502 if (Offset.isZero()) {
3503 if (
const Descriptor *Desc = Ptr.getFieldDesc();
3504 Desc && Desc->isArray() && Ptr.getIndex() == 0) {
3512 assert(!Offset.isZero());
3514 if (std::optional<Pointer>
Result =
3530template <PrimType Name, class T = typename PrimConv<Name>::T>
3538template <PrimType Name, class T = typename PrimConv<Name>::T>
3546template <PrimType Name, class T = typename PrimConv<Name>::T>
3553 assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
3558template <PrimType Name, class T = typename PrimConv<Name>::T>
3565 assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
3570template <PrimType Name, class T = typename PrimConv<Name>::T>
3572 uint32_t DestIndex, uint32_t Size) {
3576 if (SrcPtr.isDummy() || DestPtr.
isDummy())
3582 const Descriptor *SrcDesc = SrcPtr.getFieldDesc();
3588 for (uint32_t I = 0; I != Size; ++I) {
3594 DestPtr.
elem<
T>(DestIndex + I) = SrcPtr.elem<
T>(SrcIndex + I);
3610 if (!Ptr.isZeroSizeArray()) {
3616 if (Ptr.isBlockPointer()) {
3621 if (Ptr.isStringPointer()) {
3626 if (!Ptr.isOpaquePointer()) {
3639 diag::note_constexpr_unsupported_unsized_array);
3645 APSInt(APInt::getZero(1),
true),
3650 diag::note_constexpr_unsupported_unsized_array);
3660template <PrimType Name, class T = typename PrimConv<Name>::T>
3665 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
3670 if (IntVal.getOffset() != 0)
3676 if (IntVal.getOffset() != 0)
3679 const Block *B = (
const Block *)IntVal.getPtr();
3686 uint64_t NullValue =
3689 static_cast<uint64_t
>(IntVal) == NullValue);
3713 S.
FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)
3817 diag::note_constexpr_access_volatile_type)
3829 S.
CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
3837 diag::note_constexpr_pseudo_destructor);
3849 S.
CCEDiag(Loc, diag::note_constexpr_assumption_failed);
3853template <PrimType Name, class T = typename PrimConv<Name>::T>
3857 ArrayIndices.emplace_back(
3869template <PrimType Name, class T = typename PrimConv<Name>::T>
3876 S.
CCEDiag(Loc, diag::note_non_null_attribute_failed);
3882 const APSInt &
Value);
3884template <PrimType Name, class T = typename PrimConv<Name>::T>
3902 const FromT &OldPtr = S.
Stk.
pop<FromT>();
3904 if constexpr (std::is_same_v<FromT, FunctionPointer> &&
3905 std::is_same_v<ToT, Pointer>) {
3908 }
else if constexpr (std::is_same_v<FromT, Pointer> &&
3909 std::is_same_v<ToT, FunctionPointer>) {
3910 if (OldPtr.isFunctionPointer()) {
3912 OldPtr.getByteOffset());
3917 S.
Stk.
push<ToT>(ToT(OldPtr.getIntegerRepresentation(),
nullptr));
3947 if (!Ptr.isUnknownSizeArray() && NumElems > Ptr.getNumElems()) {
3949 << Ptr.getNumElems() << NumElems;
3970template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
3985 if (NumElements.isNegative()) {
3995 if (!
CheckArraySize(S, OpPC,
static_cast<uint64_t
>(NumElements)))
3999 Block *B = Allocator.
allocate(Source,
T,
static_cast<size_t>(NumElements),
4002 if (NumElements.isZero())
4009template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
4029 if (NumElements.isNegative()) {
4039 if (!
CheckArraySize(S, OpPC,
static_cast<uint64_t
>(NumElements)))
4043 Block *B = Allocator.
allocate(ElementDesc,
static_cast<size_t>(NumElements),
4046 if (NumElements.isZero())
4054bool Free(InterpState &S, CodePtr OpPC,
bool DeleteIsArrayForm,
4055 bool IsGlobalDelete);
4069 std::optional<uint64_t> ArraySize = std::nullopt);
4071template <PrimType Name, class T = typename PrimConv<Name>::T>
4073 const auto &Size = S.
Stk.
pop<
T>();
4079template <PrimType Name, class T = typename PrimConv<Name>::T>
4081 uint32_t ResultBitWidth,
const llvm::fltSemantics *Sem,
4082 const Type *TargetType) {
4088 if constexpr (std::is_same_v<T, Pointer>) {
4091 diag::note_constexpr_bit_cast_invalid_type)
4092 <<
true <<
false << 1 ;
4098 }
else if constexpr (std::is_same_v<T, MemberPointer>) {
4100 diag::note_constexpr_bit_cast_invalid_type)
4101 <<
true <<
false << 2 ;
4105 size_t BuffSize = ResultBitWidth / 8;
4107 bool HasIndeterminateBits =
false;
4109 Bits FullBitWidth(ResultBitWidth);
4110 Bits BitWidth = FullBitWidth;
4112 if constexpr (std::is_same_v<T, Floating>) {
4114 BitWidth =
Bits(llvm::APFloatBase::getSizeInBits(*Sem));
4117 if (!
DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,
4118 HasIndeterminateBits))
4121 if (!
CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
4124 if constexpr (std::is_same_v<T, Floating>) {
4131 T::bitcastFromMemory(Buff.data(), ResultBitWidth, &
Result);
4133 }
else if constexpr (std::is_same_v<T, Boolean>) {
4137 auto Val =
static_cast<unsigned int>(Buff[0]);
4140 diag::note_constexpr_bit_cast_unrepresentable_value)
4144 S.
Stk.
push<
T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
4147 S.
Stk.
push<
T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
4177bool DiagTypeid(InterpState &S, CodePtr OpPC);
4185 const void *Operand) {
4200 if constexpr (std::is_pointer<T>::value)
4203 return OpPC.
read<
T>();
4212 OpPC +=
align(F.bytesToSerialize());
4221 assert(
Result.bitWidth() == BitWidth);
4233 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
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 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 CheckDeleteSource(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Check the source of the pointer passed to delete/delete[] has actually been heap allocated by us.
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 GetPtrDerivedPop(InterpState &S, CodePtr OpPC, bool NullOK, const Type *TargetType, const Type *FinalType)
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 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 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 ReflectValue(InterpState &S, CodePtr OpPC, ReflectionKind Kind, const void *Operand)
bool StoreActivatePop(InterpState &S, CodePtr OpPC)
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 CheckPlacementNew(InterpState &S, CodePtr OpPC, const Expr *E)
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...
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