26#include "llvm/ADT/StringExtras.h"
31#if __has_cpp_attribute(clang::musttail)
32#define MUSTTAIL [[clang::musttail]]
33#elif __has_cpp_attribute(msvc::musttail)
34#define MUSTTAIL [[msvc::musttail]]
35#elif __has_attribute(musttail)
36#define MUSTTAIL __attribute__((musttail))
43#if defined(_MSC_VER) || defined(__powerpc__) || !defined(MUSTTAIL) || \
44 defined(__i386__) || defined(__sparc__)
47#define USE_TAILCALLS 0
49#define USE_TAILCALLS 1
53 llvm::report_fatal_error(
"Interpreter cannot return values");
82 S.
FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;
117 S.
FFDiag(Loc, diag::note_constexpr_access_unknown_variable, 1)
119 S.
Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();
121 S.
FFDiag(Loc, diag::note_constexpr_function_param_value_unknown, 1) << D;
131 }
else if (
const auto *VD = dyn_cast<VarDecl>(D)) {
132 if (!VD->getAnyInitializer()) {
136 S.
FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
137 S.
Note(VD->getLocation(), diag::note_declared_at);
155 if (
const auto *VarD = dyn_cast<VarDecl>(VD);
156 VarD && VarD->getType().isConstQualified() &&
157 !VarD->getAnyInitializer()) {
168 S.
FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;
174 S.
getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr
175 : diag::note_constexpr_ltor_non_integral,
187 const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(
198 S.
FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
240 const Expr *
const *Args =
nullptr;
241 unsigned NumArgs = 0;
243 if (
const auto *CE = dyn_cast<CallExpr>(CallSite)) {
244 Args = CE->getArgs();
245 NumArgs = CE->getNumArgs();
246 }
else if (
const auto *CE = dyn_cast<CXXConstructExpr>(CallSite)) {
247 Args = CE->getArgs();
248 NumArgs = CE->getNumArgs();
250 assert(
false &&
"Can't get arguments from that expression type");
252 assert(NumArgs >=
Func->getNumWrittenParams());
253 NumVarArgs = NumArgs - (
Func->getNumWrittenParams() +
255 for (
unsigned I = 0; I != NumVarArgs; ++I) {
256 const Expr *A = Args[NumArgs - 1 - I];
266 if (
Func->hasThisPointer() && !
Func->isThisPointerExplicit())
314 while (!
U.isRoot() && !
U.isActive()) {
319 if (
U.getRecord() &&
U.getRecord()->isAnonymousUnion())
326 assert(
C.getBase() ==
U);
340 if (!
U.getFieldDesc()->isUnion())
350 if (
const auto *CXXRD = dyn_cast<CXXRecordDecl>(R->getDecl());
351 CXXRD && !CXXRD->hasTrivialDefaultConstructor()) {
363 assert(!
C.isActive());
364 const FieldDecl *InactiveField =
C.getField();
365 assert(InactiveField);
368 const Record *R =
U.getRecord();
369 assert(R && R->isUnion() &&
"Not a union");
372 for (
const Record::Field &F : R->fields()) {
373 const Pointer &Field =
U.atField(F.Offset);
374 if (Field.isActive()) {
375 ActiveField = Field.getField();
381 S.
FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)
382 << AK << InactiveField << !ActiveField << ActiveField;
408 S.
FFDiag(E, diag::note_constexpr_unsized_array_indexed);
420 S.
FFDiag(Src, diag::note_constexpr_access_null) << AK;
429 S.
FFDiag(Src, diag::note_constexpr_access_deleted_object) << AK;
431 S.
FFDiag(Src, diag::note_constexpr_access_uninit)
452 if (
const auto *VD = dyn_cast_if_present<VarDecl>(S.
EvaluatingDecl);
458 if (T->isIntegralOrEnumerationType()) {
470 ? diag::note_constexpr_ltor_non_constexpr
471 : diag::note_constexpr_ltor_non_integral,
474 S.
Note(D->getLocation(), diag::note_declared_at);
481 if (T->isPointerOrReferenceType()) {
507 S.
FFDiag(Loc, diag::note_constexpr_null_subobject)
519 S.
FFDiag(Loc, diag::note_constexpr_access_past_end)
530 S.
FFDiag(Loc, diag::note_constexpr_past_end_subobject)
541 S.
FFDiag(Loc, diag::note_constexpr_past_end_subobject)
553 if (Offset < PtrOffset && (PtrOffset - Offset) >= MinOffset)
560 S.
CCEDiag(E, diag::note_constexpr_invalid_downcast)
561 << MostDerivedQT << TargetQT;
567 assert(Ptr.
isLive() &&
"Pointer is not live");
585 S.
FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
591 assert(Ptr.
isLive() &&
"Pointer is not live");
602 S.
FFDiag(Loc, diag::note_constexpr_access_mutable, 1) <<
AK_Read << Field;
603 S.
Note(Field->getLocation(), diag::note_declared_at);
635 Loc = F->getLocation();
639 Loc = VD->getLocation();
644 Loc = E->getExprLoc();
648 diag::note_constexpr_access_volatile_obj, 1)
649 << AK << DiagKind << ND;
650 S.
Note(Loc, diag::note_constexpr_volatile_here) << DiagKind;
669 VD && (VD->isConstexpr() || VD->hasGlobalStorage())) {
672 !(S.
getLangOpts().CPlusPlus23 && VD->getType()->isReferenceType())) {
680 S.
FFDiag(Loc, diag::note_constexpr_access_uninit)
682 S.
Note(VD->getLocation(), diag::note_declared_at);
687 if (VD->getAnyInitializer()) {
689 S.
FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
690 S.
Note(VD->getLocation(), diag::note_declared_at);
730 S.
Note(VD->getLocation(), diag::note_declared_at);
761 diag::note_constexpr_access_volatile_obj, 1)
775 if (!Desc.IsInitialized)
783 diag::note_constexpr_access_volatile_obj, 1)
799 S.
FFDiag(Src, diag::note_constexpr_access_null) << AK;
851 if (
const auto *CLE =
852 dyn_cast_if_present<CompoundLiteralExpr>(Desc->
asExpr())) {
853 if (
QualType CLETy = CLE->getType();
856 diag::note_invalid_subexpr_in_const_expr)
858 S.
Note(CLE->getExprLoc(), diag::note_declared_at);
902 bool WillBeActivated) {
931 bool IsCtorDtor =
false) {
965 StringRef Name = DiagDecl->
getName();
967 Name ==
"__assert_rtn" || Name ==
"__assert_fail" || Name ==
"_wassert";
970 diag::note_constexpr_assert_failed);
977 diag::note_invalid_subexpr_in_const_expr);
987 const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
988 if (CD && CD->isInheritingConstructor()) {
989 const auto *Inherited = CD->getInheritedConstructor().getConstructor();
990 if (!Inherited->isConstexpr())
991 DiagDecl = CD = Inherited;
996 if (CD && CD->getParent()->isInvalidDecl())
1002 if (CD && CD->isInheritingConstructor()) {
1005 << CD->getInheritedConstructor().getConstructor()->getParent();
1013 if (!IsDefined && !IsExtern && DiagDecl->
isConstexpr() &&
1023 diag::note_constexpr_invalid_function, 1)
1024 << DiagDecl->
isConstexpr() << (bool)CD << DiagDecl;
1038 S.
CCEDiag(Loc, diag::note_constexpr_virtual_call);
1066 diag::note_constexpr_depth_limit_exceeded)
1080 bool IsImplicit =
false;
1081 if (
const auto *TE = dyn_cast<CXXThisExpr>(E))
1082 IsImplicit = TE->isImplicit();
1083 S.
FFDiag(E, diag::note_constexpr_this) << IsImplicit;
1092 APFloat::opStatus Status,
FPOptions FPO) {
1099 S.
CCEDiag(E, diag::note_constexpr_float_arithmetic)
1109 if ((Status & APFloat::opInexact) &&
1114 S.
FFDiag(E, diag::note_constexpr_dynamic_rounding);
1118 if ((Status != APFloat::opOK) &&
1121 FPO.getAllowFEnvAccess())) {
1123 S.
FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
1127 if ((Status & APFloat::opStatus::opInvalidOp) &&
1143 S.
CCEDiag(E, diag::note_constexpr_new);
1150 const Expr *NewExpr) {
1151 if (AllocForm == DeleteForm)
1157 S.
FFDiag(E, diag::note_constexpr_new_delete_mismatch)
1158 <<
static_cast<int>(DeleteForm) <<
static_cast<int>(AllocForm)
1160 S.
Note(NewExpr->
getExprLoc(), diag::note_constexpr_dynamic_alloc_here)
1168 if (isa_and_nonnull<CXXNewExpr>(Source))
1171 if (
const auto *CE = dyn_cast_if_present<CallExpr>(Source);
1172 CE && CE->getBuiltinCallee() == Builtin::BI__builtin_operator_new)
1175 if (
const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(Source);
1176 MCE && MCE->getMethodDecl()->
getIdentifier()->isStr(
"allocate"))
1181 S.
FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)
1201 S.
FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
1202 S.
Note(VD->getLocation(), diag::note_declared_at);
1222 S.
FFDiag(E, diag::note_constexpr_modify_global);
1228 const CallExpr *CE,
unsigned ArgSize) {
1231 unsigned Offset = 0;
1233 for (
const Expr *Arg : Args) {
1234 if (NonNullArgs[Index] && Arg->getType()->isPointerType()) {
1238 S.
CCEDiag(Loc, diag::note_non_null_attribute_failed);
1260 S.
FFDiag(Loc, diag::note_constexpr_double_destroy);
1273 return Call(S, OpPC, DtorFunc, 0);
1296 for (
int I =
static_cast<int>(N) - 1; I >= 0; --I) {
1310 return DD->isVirtual();
1315 bool IsGlobalDelete) {
1321 const Expr *Source =
nullptr;
1322 const Block *BlockToDelete =
nullptr;
1337 BlockToDelete = Ptr.
block();
1341 if (std::optional<DynamicAllocator::Form> AllocForm =
1353 if (!DeleteIsArrayForm && Ptr.
getType() != InitialType &&
1356 diag::note_constexpr_delete_base_nonvirt_dtor)
1357 << InitialType << Ptr.
getType();
1364 S.
FFDiag(Loc, diag::note_constexpr_delete_subobject)
1374 if (!DeleteIsArrayForm && !IsGlobalDelete) {
1379 return DD->isVirtual() ? DD->getOperatorDelete() :
nullptr;
1389 diag::note_constexpr_new_non_replaceable)
1396 assert(BlockToDelete);
1402 if (!Allocator.
deallocate(Source, BlockToDelete, S)) {
1405 S.
FFDiag(Loc, diag::note_constexpr_double_delete);
1422 S.
CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)
1423 << llvm::toString(
Value, 10) <<
Min.getSExtValue() <<
Max.getSExtValue()
1427 S.
CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)
1428 << llvm::toString(
Value, 10) <<
Min.getZExtValue() <<
Max.getZExtValue()
1459 S.
FFDiag(E, diag::note_constexpr_nonliteral) << E->
getType();
1461 S.
FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
1479 if (std::optional<IntPointer> IntPtr =
1492 diag::note_constexpr_access_unreadable_object)
1510 return getField(S, OpPC, Ptr, Off);
1515 return getField(S, OpPC, Ptr, Off);
1519 uint32_t Off,
bool NullOK) {
1549 return getBase(S, OpPC, Ptr.narrow(), Off,
true);
1553 return getBase(S, OpPC, Ptr.narrow(), Off, NullOK);
1557 const Type *TargetType) {
1581 assert(TargetRecord);
1587 << MostDerivedType <<
QualType(TargetType, 0);
1597 assert(
Func->isConstructor());
1599 if (
Func->getParentDecl()->isInvalidDecl())
1612 <<
Func->getParentDecl();
1622 S.
FFDiag(ND->getLocation(), diag::note_constexpr_destroy_out_of_lifetime)
1623 << ND->getNameAsString();
1626 diag::note_constexpr_destroy_out_of_lifetime)
1648 S.
FFDiag(E, diag::note_constexpr_modify_global);
1671 bool SrcIsVoidPtr) {
1675 if (!Ptr.isBlockPointer())
1682 bool HasValidResult = !Ptr.isZero();
1684 if (HasValidResult) {
1694 S.
CCEDiag(E, diag::note_constexpr_invalid_void_star_cast)
1695 << E->getSubExpr()->getType() << S.
getLangOpts().CPlusPlus26
1696 << Ptr.getType().getCanonicalType() << E->getType()->getPointeeType();
1699 S.
CCEDiag(E, diag::note_constexpr_invalid_cast)
1700 << diag::ConstexprInvalidCastKind::CastFrom <<
"'void *'"
1709 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
1726 uint32_t VarArgSize) {
1727 if (
Func->hasThisPointer()) {
1728 size_t ArgSize =
Func->getArgSize() + VarArgSize;
1738 Func->isLambdaCallOperator())) {
1747 if (!
Func->isFullyCompiled())
1765 assert(S.
Current == FrameBefore);
1776 uint32_t VarArgSize) {
1783 auto cleanup = [&]() ->
bool {
1788 if (
Func->hasThisPointer()) {
1789 size_t ArgSize =
Func->getArgSize() + VarArgSize;
1806 Func->isLambdaCallOperator()) {
1807 assert(ThisPtr.
isZero());
1810 Func->isConstructor() ||
Func->isDestructor()))
1813 if (
Func->isCopyOrMoveOperator() ||
Func->isCopyOrMoveConstructor()) {
1820 if (!
Func->isConstructor() && !
Func->isDestructor() &&
1830 if (
Func->isConstructor() ||
Func->isDestructor())
1834 if (!
Func->isFullyCompiled())
1860 if (
Func->isConstructor() ||
Func->isDestructor())
1871 assert(S.
Current == FrameBefore);
1886 S.
FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
1893 DynamicDecl =
DynamicType->getPointeeCXXRecordDecl();
1901 return DynamicDecl !=
nullptr;
1905 uint32_t VarArgSize) {
1906 assert(
Func->hasThisPointer());
1907 assert(
Func->isVirtual());
1908 size_t ArgSize =
Func->getArgSize() + VarArgSize;
1916 assert(DynamicDecl);
1922 if (StaticDecl != DynamicDecl &&
1930 Overrider = InitialFunction;
1940 S.
Note(Callee->getLocation(), diag::note_declared_at);
1944 if (Overrider != InitialFunction) {
1957 if (
Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
1965 if (!
Call(S, OpPC,
Func, VarArgSize))
1970 if (Overrider != InitialFunction &&
1972 InitialFunction->getReturnType()->isPointerOrReferenceType()) {
1991 uint32_t BuiltinID) {
1994 if (BuiltinID == Builtin::BI__builtin_operator_new &&
2058 return CallVirt(S, OpPC, F, VarArgSize);
2060 return Call(S, OpPC, F, VarArgSize);
2067 for (
const Record::Field &Fi : R->fields()) {
2077 for (
unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
2093 if (!Ptr.isBlockPointer())
2104 if (!Ptr.isBlockPointer())
2115 for (
const Record::Field &Fi : R->fields())
2125 for (
unsigned I = 0; I != FieldDesc->getNumElems(); ++I)
2163 std::optional<uint64_t> ArraySize) {
2166 auto directBaseIsUnion = [](
const Pointer &Ptr) ->
bool {
2170 return R && R->isUnion();
2173 if (Ptr.
inUnion() && directBaseIsUnion(Ptr))
2230 NewExpr->getAllocatedType(),
2231 APInt(64,
static_cast<uint64_t
>(*ArraySize),
false),
nullptr,
2234 AllocType = NewExpr->getAllocatedType();
2237 unsigned StorageSize = 1;
2238 unsigned AllocSize = 1;
2239 if (
const auto *CAT = dyn_cast<ConstantArrayType>(AllocType))
2240 AllocSize = CAT->getZExtSize();
2241 if (
const auto *CAT = dyn_cast<ConstantArrayType>(StorageType))
2242 StorageSize = CAT->getZExtSize();
2244 if (AllocSize > StorageSize ||
2248 diag::note_constexpr_placement_new_wrong_type)
2249 << StorageType << AllocType;
2263 if (
const auto *NewExpr = dyn_cast<CXXNewExpr>(E)) {
2264 const FunctionDecl *OperatorNew = NewExpr->getOperatorNew();
2266 if (NewExpr->getNumPlacementArgs() > 0) {
2277 ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
2279 diag::note_constexpr_new_non_replaceable)
2283 NewExpr->getNumPlacementArgs() == 1 &&
2284 !OperatorNew->isReservedGlobalPlacementOperator()) {
2294 const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelete();
2296 ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
2298 diag::note_constexpr_new_non_replaceable)
2312 E->
getExprLoc(), diag::warn_fixedpoint_constant_overflow)
2315 S.
CCEDiag(E, diag::note_constexpr_overflow)
2323 diag::err_shufflevector_minus_one_is_undefined_behavior_constexpr)
2329 const Pointer &Ptr,
unsigned BitWidth) {
2331 S.
CCEDiag(E, diag::note_constexpr_invalid_cast)
2383 bool TargetIsUCharOrByte) {
2385 if (!HasIndeterminateBits)
2389 if (TargetIsUCharOrByte)
2394 S.
FFDiag(E, diag::note_constexpr_bit_cast_indet_dest)
2406 if (!ID.IsInitialized) {
2409 diag::note_constexpr_use_uninit_reference);
2419 const Type *TypeInfoType) {
2427 if (!P.isBlockPointer())
2431 CanQualType T = P.getDeclPtr().getType()->getCanonicalTypeUnqualified();
2437 Func && (
Func->isConstructor() ||
Func->isDestructor()) &&
2438 P.block() ==
Frame->getThis().block()) {
2440 Func->getParentDecl());
2452 S.
CCEDiag(E, diag::note_constexpr_typeid_polymorphic)
2453 << E->getExprOperand()->getType()
2454 << E->getExprOperand()->getSourceRange();
2468 StringRef LHSStr(LHSLit->getBytes());
2469 unsigned LHSLength = LHSStr.size();
2470 StringRef RHSStr(RHSLit->getBytes());
2471 unsigned RHSLength = RHSStr.size();
2473 int32_t IndexDiff = RHSOffset - LHSOffset;
2474 if (IndexDiff < 0) {
2475 if (
static_cast<int32_t
>(LHSLength) < -IndexDiff)
2477 LHSStr = LHSStr.drop_front(-IndexDiff);
2479 if (
static_cast<int32_t
>(RHSLength) < IndexDiff)
2481 RHSStr = RHSStr.drop_front(IndexDiff);
2484 unsigned ShorterCharWidth;
2487 if (LHSLength < RHSLength) {
2500 for (
unsigned NullByte : llvm::seq(ShorterCharWidth)) {
2501 if (Shorter.size() + NullByte >= Longer.size())
2503 if (Longer[Shorter.size() + NullByte])
2506 return Shorter == Longer.take_front(Shorter.size());
2513 if (!Val.singleWord()) {
2514 uint64_t *NewMemory =
new (S.
P) uint64_t[Val.numWords()];
2515 Val.take(NewMemory);
2519 if (!Val.singleWord()) {
2520 uint64_t *NewMemory =
new (S.
P) uint64_t[Val.numWords()];
2521 Val.take(NewMemory);
2525 if (!Val.singleWord()) {
2526 uint64_t *NewMemory =
new (S.
P) uint64_t[Val.numWords()];
2527 Val.take(NewMemory);
2533 std::copy_n(Val.path(), PathLength, NewPath);
2534 Val.takePath(NewPath);
2538template <
typename T>
2541 if constexpr (std::is_same_v<T, MemberPointer>) {
2545 std::copy_n(Val.path(), PathLength, NewPath);
2546 Val.takePath(NewPath);
2548 auto &Val = Ptr.
deref<T>();
2549 if (!Val.singleWord()) {
2550 uint64_t *NewMemory =
new (S.
P) uint64_t[Val.numWords()];
2551 Val.take(NewMemory);
2558 for (
const Record::Field &Fi : R->fields()) {
2559 if (Fi.Desc->isPrimitive()) {
2561 copyPrimitiveMemory<T>(S, Ptr.atField(Fi.Offset));
2571 unsigned NumElems = D->getNumElems();
2575 if (D->isPrimitiveArray()) {
2579 assert(NumElems >= 1);
2581 bool AllSingleWord =
true;
2583 if (!EP.
deref<T>().singleWord()) {
2585 AllSingleWord =
false;
2590 for (
unsigned I = 1; I != D->getNumElems(); ++I) {
2595 assert(D->isCompositeArray());
2596 for (
unsigned I = 0; I != D->getNumElems(); ++I) {
2621 S.
CCEDiag(Loc, diag::note_constexpr_invalid_cast)
2622 << diag::ConstexprInvalidCastKind::Reinterpret
2626 S.
CCEDiag(Loc, diag::note_constexpr_invalid_cast)
2627 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
2634 S.
FFDiag(E, diag::note_constexpr_access_volatile_type)
2635 <<
AK_Read << E->getSubExpr()->getType();
2643 S.
CCEDiag(Loc, diag::note_constexpr_invalid_cast)
2644 << diag::ConstexprInvalidCastKind::Dynamic;
2647 llvm_unreachable(
"Unhandled CastKind");
2674 if (MemberPtr.getPathLength() >= 2)
2675 Expected = MemberPtr.getPathEntry(MemberPtr.getPathLength() - 2);
2677 Expected = MemberPtr.getRecordDecl();
2690 unsigned OldPathLength = MemberPtr.getPathLength();
2691 unsigned NewPathLength = OldPathLength - 1;
2692 bool IsDerivedMember = NewPathLength != 0;
2694 std::copy_n(MemberPtr.path(), NewPathLength, NewPath);
2697 NewPath, IsDerivedMember));
2705 bool IsDerivedMember) {
2706 unsigned OldPathLength = MemberPtr.getPathLength();
2707 unsigned NewPathLength = OldPathLength + 1;
2710 std::copy_n(MemberPtr.path(), OldPathLength, NewPath);
2714 NewPath, IsDerivedMember));
2723 if (!Ptr.isDerivedMember() && Ptr.hasPath())
2726 bool IsDerivedMember = Ptr.isDerivedMember() || !Ptr.hasPath();
2735 if (!Ptr.isDerivedMember()) {
2752 if (!MP.isBaseCastPossible())
2763 const auto *FD = dyn_cast_if_present<FunctionDecl>(D);
2767 const auto *
Method = dyn_cast<CXXMethodDecl>(FD);
2774 if (!
Base.getRecord() ||
Base.getRecord()->getDecl() != MethodParent)
2791 unsigned NewPathLength = OldPathLength + 1;
2794 std::copy_n(MemberPtr.path(), OldPathLength, NewPath);
2798 MemberPtr.withPath(NewPathLength, NewPath, IsDerived));
2804 return Op == OP_RetVoid || Op == OP_RetValue || Op == OP_NoRet ||
2805 Op == OP_RetSint8 || Op == OP_RetUint8 || Op == OP_RetSint16 ||
2806 Op == OP_RetUint16 || Op == OP_RetSint32 || Op == OP_RetUint32 ||
2807 Op == OP_RetSint64 || Op == OP_RetUint64 || Op == OP_RetIntAP ||
2808 Op == OP_RetIntAPS || Op == OP_RetBool || Op == OP_RetFixedPoint ||
2809 Op == OP_RetPtr || Op == OP_RetMemberPtr || Op == OP_RetFloat ||
2810 Op == OP_EndSpeculation;
2819#define GET_INTERPFN_DISPATCHERS
2820#include "Opcodes.inc"
2821#undef GET_INTERPFN_DISPATCHERS
2826#define GET_INTERPFN_LIST
2827#include "Opcodes.inc"
2828#undef GET_INTERPFN_LIST
2849 return InterpNext(S, PC);
2876 [[maybe_unused]]
CodePtr PCBefore = RealPC;
2877 size_t StackSizeBefore = S.
Stk.
size();
2883 assert(DepthBefore >= 1);
2887 auto SpeculativeInterp = [&S, &PC]() ->
bool {
2910 if (SpeculativeInterp()) {
2915 assert(S.
Stk.
size() == StackSizeBefore);
2921 assert(S.
Stk.
size() == StackSizeBefore);
2937 assert(*RealPC == *PCBefore);
2947 assert(Offset >= ParamSize);
2948 RealPC += Offset - ParamSize;
Defines the clang::ASTContext interface.
Defines the clang::Expr interface and subclasses for C++ expressions.
static const FunctionDecl * getVirtualOperatorDelete(QualType T)
static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset)
static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK)
static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
static PRESERVE_NONE bool RetValue(InterpState &S, CodePtr &Ptr)
static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset)
static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, const ValueDecl *VD)
static void noteValueLocation(InterpState &S, const Block *B)
static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC, const ValueDecl *D)
static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset)
static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC, const ValueDecl *VD)
static StringRef getIdentifier(const Token &Tok)
#define TYPE_SWITCH_ALLOC(Expr, B)
#define TYPE_SWITCH(Expr, B)
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
bool hasSameFunctionTypeIgnoringExceptionSpec(QualType T, QualType U) const
Determine whether two function types are the same, ignoring exception specifications in cases where t...
QualType getLValueReferenceType(QualType T, bool SpelledAsLValue=true) const
Return the uniqued reference to the type for an lvalue reference 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.
bool hasSimilarType(QualType T1, QualType T2) const
Determine if two types are similar, according to the C++ rules.
DiagnosticsEngine & getDiagnostics() const
const TargetInfo & getTargetInfo() const
CanQualType getCanonicalTagType(const TagDecl *TD) const
Represents a C++ destructor within a class.
Represents a static or instance method of a struct/union/class.
Represents a C++ struct/union/class.
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
bool isDerivedFrom(const CXXRecordDecl *Base) const
Determine whether this class is derived from the class Base.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Expr ** getArgs()
Retrieve the call arguments.
QualType getCallReturnType(const ASTContext &Ctx) const
getCallReturnType - Get the return type of the call expr.
A reference to a declared variable, function, enum, etc.
Decl - This represents one declaration (or definition), e.g.
bool isInvalidDecl() const
SourceLocation getLocation() const
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
unsigned getNumNegativeBits() const
Returns the width in bits required to store all the negative enumerators of this enum.
void getValueRange(llvm::APInt &Max, llvm::APInt &Min) const
Calculates the [Min,Max) values the enum can store based on the NumPositiveBits and NumNegativeBits.
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...
LangOptions::FPExceptionModeKind getExceptionMode() const
RoundingMode getRoundingMode() const
Represents a member of a struct/union/class.
Represents a function declaration or definition.
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
QualType getReturnType() const
bool isTrivial() const
Whether this function is "trivial" in some specialized C++ senses.
StorageClass getStorageClass() const
Returns the storage class as written in the source.
bool isConstexpr() const
Whether this is a (C++11) constexpr function or constexpr constructor.
bool isPureVirtual() const
Whether this virtual function is pure, i.e.
bool isUsableAsGlobalAllocationFunctionInConstantEvaluation(UnsignedOrNone *AlignmentParam=nullptr, bool *IsNothrow=nullptr) const
Determines whether this function is one of the replaceable global allocation functions described in i...
FunctionDecl * getDefinition()
Get the definition for this declaration.
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
bool isDefined(const FunctionDecl *&Definition, bool CheckForPendingFriendDefinition=false) const
Returns true if the function has a definition that does not need to be instantiated.
@ FPE_Ignore
Assume that floating-point exceptions are masked.
This represents a decl that may have a name.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
A (possibly-)qualified type.
bool isVolatileQualified() const
Determine whether this type is volatile-qualified.
bool isConstQualified() const
Determine whether this type is const-qualified.
Represents a struct/union/class.
Encodes a location in the source.
Stmt - This represents one statement.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
TagDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
uint64_t getPointerWidth(LangAS AddrSpace) const
Return the width of pointers on this target, for the specified address space.
The base class of the type hierarchy.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
bool isPointerType() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
bool isReferenceType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
bool isAnyComplexType() const
bool isPointerOrReferenceType() const
bool isRecordType() 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 isConstexpr() const
Whether this variable is (C++11) constexpr.
A memory block, either on the stack or in the heap.
unsigned getSize() const
Returns the size of the block.
bool isExtern() const
Checks if the block is extern.
const Descriptor * getDescriptor() const
Returns the block's descriptor.
bool isStatic() const
Checks if the block has static storage duration.
bool isTemporary() const
Checks if the block is temporary.
std::byte * rawData()
Returns a pointer to the raw data, including metadata.
bool isInitialized() const
Returns whether the data of this block has been initialized via invoking the Ctor func.
UnsignedOrNone getDeclID() const
Returns the declaration ID.
unsigned getEvalID() const
The Evaluation ID this block was created in.
bool isAccessible() const
Pointer into the code segment.
std::enable_if_t<!std::is_pointer< T >::value, T > read()
Reads data and advances the pointer.
Compilation context for expressions.
unsigned collectBaseOffset(const RecordDecl *BaseDecl, const RecordDecl *DerivedDecl) const
const Function * getOrCreateFunction(const FunctionDecl *FuncDecl)
ASTContext & getASTContext() const
Returns the AST context.
OptPrimType classify(QualType T) const
Classifies a type.
const CXXMethodDecl * getOverridingFunction(const CXXRecordDecl *DynamicDecl, const CXXRecordDecl *StaticDecl, const CXXMethodDecl *InitialFunction) const
Manages dynamic memory allocations done during bytecode interpretation.
bool deallocate(const Expr *Source, const Block *BlockToDelete, InterpState &S)
Deallocate the given source+block combination.
std::optional< Form > getAllocationForm(const Expr *Source) const
Checks whether the allocation done at the given source is an array allocation.
Wrapper around fixed point types.
std::string toDiagnosticString(const ASTContext &Ctx) const
If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.
Base class for stack frames, shared between VM and walker.
Scope & getScope(unsigned Idx)
Returns a specific scope.
bool isDestructor() const
Checks if the function is a destructor.
bool isVirtual() const
Checks if the function is virtual.
bool hasNonNullAttr() const
bool isFullyCompiled() const
Checks if the function is fully done compiling.
bool isConstructor() const
Checks if the function is a constructor.
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
bool hasBody() const
Checks if the function already has a body attached.
bool isThisPointerExplicit() const
unsigned getWrittenArgSize() const
bool isLambdaStaticInvoker() const
Returns whether this function is a lambda static invoker, which we generate custom byte code for.
bool isValid() const
Checks if the function is valid to call.
If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY.
Wrapper around numeric types.
static std::enable_if_t<!std::is_same_v< ValT, IntegralKind >, Integral > from(ValT V, unsigned NumBits=0)
Frame storing local variables.
static void free(InterpFrame *F)
const Expr * getExpr(CodePtr PC) const
InterpFrame * Caller
The frame of the previous function.
SourceInfo getSource(CodePtr PC) const
Map a location to a source.
CodePtr getRetPC() const
Returns the return address of the frame.
Block * getLocalBlock(unsigned Offset) const
CodePtr getPC() const
Returns the PC of the frame's code start.
SourceLocation getLocation(CodePtr PC) const
const Pointer & getThis() const
Returns the 'this' pointer.
unsigned MSVCConstexprAllowed
const Function * getFunction() const
Returns the current function.
SourceRange getRange(CodePtr PC) const
bool isBottomFrame() const
bool isRoot() const
Checks if the frame is a root frame - return should quit the interpreter.
bool hasThisPointer() const
Pointer getLocalPointer(unsigned Offset) const
Returns a pointer to a local variables.
unsigned getDepth() const
void destroy(unsigned Idx)
Invokes the destructors for a scope.
bool isStdFunction() const
static size_t allocSize(const Function *F)
Returns the number of bytes needed to allocate an InterpFrame for the given function.
void clearTo(size_t NewSize)
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.
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.
Context & getContext() const
DynamicAllocator & getAllocator()
Context & Ctx
Interpreter Context.
bool noteStep(CodePtr OpPC)
Note that a step has been executed.
const unsigned EvalID
ID identifying this evaluation.
llvm::SmallVector< const Block * > InitializingBlocks
List of blocks we're currently running either constructors or destructors for.
InterpStack & Stk
Temporary stack.
const VarDecl * EvaluatingDecl
Declaration we're initializing/evaluting, if any.
InterpFrame * Current
The current frame.
const CXXRecordDecl ** allocMemberPointerPath(unsigned Length)
T allocAP(unsigned BitWidth)
unsigned SpeculationDepth
StdAllocatorCaller getStdAllocatorCaller(StringRef Name) const
bool inConstantContext() const
Program & P
Reference to the module containing all bytecode.
unsigned getPathLength() const
Return the length of the cast path.
PrimType value_or(PrimType PT) const
A pointer to a memory block, live or dead.
Pointer narrow() const
Restricts the scope of an array element pointer.
UnsignedOrNone getDeclID() const
Returns the declaration ID.
Pointer stripBaseCasts() const
Strip base casts from this Pointer.
bool isVolatile() const
Checks if an object or a subfield is volatile.
bool isInitialized() const
Checks if an object was initialized.
bool isStatic() const
Checks if the storage is static.
bool isDynamic() const
Checks if the storage has been dynamically allocated.
bool isZeroSizeArray() const
Checks if the pointer is pointing to a zero-size array.
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
bool isDummy() const
Checks if the pointer points to a dummy value.
Pointer atFieldSub(unsigned Off) const
Subtract the given offset from the current Base and Offset of the pointer.
bool isExtern() const
Checks if the storage is extern.
int64_t getIndex() const
Returns the index into an array.
bool isActive() const
Checks if the object is active.
void startLifetime() const
Start the lifetime of this pointer.
bool isConst() const
Checks if an object or a subfield is mutable.
Pointer atField(unsigned Off) const
Creates a pointer to a field.
T & deref() const
Dereferences the pointer, if it's live.
bool isMutable() const
Checks if the field is mutable.
bool isConstInMutable() const
unsigned getNumElems() const
Returns the number of elements.
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
void activate() const
Activats a field.
bool isIntegralPointer() const
QualType getType() const
Returns the type of the innermost field.
bool isArrayElement() const
Checks if the pointer points to an array.
bool pointsToStringLiteral() const
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
bool isLive() const
Checks if the pointer is live.
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
uint64_t getByteOffset() const
Returns the byte offset from the start.
void setLifeState(Lifetime L) const
bool isTypeidPointer() const
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
bool isZero() const
Checks if the pointer is null.
bool isConstexprUnknown() const
const IntPointer & asIntPointer() const
bool isRoot() const
Pointer points directly to a block.
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
static bool pointToSameBlock(const Pointer &A, const Pointer &B)
Checks if both given pointers point to the same block.
APValue toAPValue(const ASTContext &ASTCtx) const
Converts the pointer to an APValue.
bool isOnePastEnd() const
Checks if the index is one past end.
uint64_t getIntegerRepresentation() const
bool isPastEnd() const
Checks if the pointer points past the end of the object.
const FieldDecl * getField() const
Returns the field information.
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
bool isBlockPointer() const
const FunctionPointer & asFunctionPointer() const
const Block * block() const
bool isFunctionPointer() const
Pointer getDeclPtr() const
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
bool canBeInitialized() const
If this pointer has an InlineDescriptor we can use to initialize.
Lifetime getLifetime() const
void initialize() const
Initializes a field.
bool isField() const
Checks if the item is a field in an object.
const Record * getRecord() const
Returns the record descriptor of a class.
UnsignedOrNone getCurrentDecl() const
Returns the current declaration ID.
Structure/Class descriptor.
const RecordDecl * getDecl() const
Returns the underlying declaration.
unsigned getNumVirtualBases() const
llvm::iterator_range< LocalVectorTy::const_reverse_iterator > locals_reverse() const
Describes the statement/declaration an opcode was generated from.
bool checkingForUndefinedBehavior() const
Are we checking an expression for overflow?
OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId)
Add a note to a prior diagnostic.
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)
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?
Defines the clang::TargetInfo interface.
bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS, const Pointer &RHS)
bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off)
static bool CheckCallDepth(InterpState &S, CodePtr OpPC)
const InterpFn InterpFunctions[]
static bool diagnoseCallableDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *DiagDecl)
constexpr bool OpReturns(Opcode Op)
static bool getDynamicDecl(InterpState &S, CodePtr OpPC, Pointer TypePtr, const CXXRecordDecl *&DynamicDecl)
static void startLifetimeRecurse(const Pointer &Ptr)
bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
static bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
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 GetMemberPtrBase(InterpState &S, CodePtr OpPC)
bool CheckFunctionDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *FD)
Opcode. Check if the function decl can be called at compile time.
static bool appendToMemberPointer(InterpState &S, const MemberPointer &MemberPtr, int32_t BaseOffset, const RecordDecl *BaseDecl, bool IsDerivedMember)
bool EndLifetimePop(InterpState &S, CodePtr OpPC)
Ends the lifetime of the pop'd pointer.
static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F)
static bool runRecordDestructor(InterpState &S, CodePtr OpPC, const Pointer &BasePtr, const Descriptor *Desc)
bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType)
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 CheckNewDeleteForms(InterpState &S, CodePtr OpPC, DynamicAllocator::Form AllocForm, DynamicAllocator::Form DeleteForm, const Descriptor *D, const Expr *NewExpr)
Diagnose mismatched new[]/delete or new/delete[] pairs.
bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B)
Checks a direct load of a primitive value from a global or local variable.
bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR)
We aleady know the given DeclRefExpr is invalid for some reason, now figure out why and print appropr...
bool EndLifetime(InterpState &S, CodePtr OpPC)
Ends the lifetime of the peek'd pointer.
bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr, const Type *TypeInfoType)
Typeid support.
static PRESERVE_NONE bool BCP(InterpState &S, CodePtr &RealPC, int32_t Offset, PrimType PT)
This is used to implement speculative execution via __builtin_constant_p when we generate bytecode.
static bool CheckWeak(InterpState &S, CodePtr OpPC, const Block *B)
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Checks if the Descriptor is of a constexpr or const global variable.
bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, unsigned BitWidth)
static bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B)
bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off)
1) Peeks a Pointer 2) Pushes Pointer.atField(Off) on the stack
bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK, bool WillActivate)
static bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *CE, unsigned ArgSize)
bool StartThisLifetime1(InterpState &S, CodePtr OpPC)
PRESERVE_NONE bool EndSpeculation(InterpState &S, CodePtr &OpPC)
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to a mutable field.
static void finishGlobalRecurse(InterpState &S, const Pointer &Ptr)
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 handleReference(InterpState &S, CodePtr OpPC, Block *B)
bool CheckBitCast(InterpState &S, CodePtr OpPC, const Type *TargetType, bool SrcIsVoidPtr)
static bool getField(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t Off)
static bool hasVirtualDestructor(QualType T)
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a value can be loaded from a block.
static bool getBase(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t Off, bool NullOK)
bool RVOPtr(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 CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is in range.
bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC)
Checks if dynamic memory allocation is available in the current language mode.
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is live and accessible.
bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off, bool NullOK, const Type *TargetType)
bool DiagTypeid(InterpState &S, CodePtr OpPC)
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
This is not used by any of the opcodes directly.
bool CopyMemberPtrPath(InterpState &S, CodePtr OpPC, const RecordDecl *Entry, bool IsDerived)
Just append the given Entry to the MemberPointer's path.
static void popArg(InterpState &S, const Expr *Arg)
static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func, const Pointer &ThisPtr)
bool PushIgnoreDiags(InterpState &S, CodePtr OpPC)
void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, const APSInt &Value)
bool CastMemberPtrDerivedPop(InterpState &S, CodePtr OpPC, int32_t Off, const RecordDecl *BaseDecl)
BaseToDerivedMemberPointer.
bool PopIgnoreDiags(InterpState &S, CodePtr OpPC)
bool isConstexprUnknown(const Block *B)
bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR, bool InitializerFailed)
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.
PrimType
Enumeration of the primitive types of the VM.
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, uint32_t BuiltinID)
Interpret a builtin function.
bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
constexpr bool needsAlloc()
bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index)
bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK)
Checks if a pointer is a dummy pointer.
static bool diagnoseOutOfLifetimeDestroy(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E, std::optional< uint64_t > ArraySize)
Check if the initializer and storage types of a placement-new expression match.
bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D)
bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T)
bool StartThisLifetime(InterpState &S, CodePtr OpPC)
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)
bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC)
static void compileFunction(InterpState &S, const Function *Func)
bool CheckThis(InterpState &S, CodePtr OpPC)
Checks the 'this' pointer.
bool FinishInitGlobal(InterpState &S, CodePtr OpPC)
void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC, const Function *Func)
bool CheckIntegralAddressCast(InterpState &S, CodePtr OpPC, unsigned BitWidth)
static void copyPrimitiveMemory(InterpState &S, const Pointer &Ptr, PrimType T)
bool CastMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off, const RecordDecl *BaseDecl)
DerivedToBaseMemberPointer.
bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I)
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm, bool IsGlobalDelete)
bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E)
bool CallBI(InterpState &S, CodePtr OpPC, const CallExpr *CE, uint32_t BuiltinID)
bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B)
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the variable has externally defined storage.
static bool CheckLifetime(InterpState &S, CodePtr OpPC, Lifetime LT, const Block *B, AccessKinds AK)
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool WillBeActivated)
Checks if a value can be stored in a block.
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off, bool NullOK)
bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
llvm::BitVector collectNonNullArgs(const FunctionDecl *F, ArrayRef< const Expr * > Args)
static bool castBackMemberPointer(InterpState &S, const MemberPointer &MemberPtr, int32_t BaseOffset, const RecordDecl *BaseDecl)
bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, const CallExpr *CE)
static void setLifeStateRecurse(const Pointer &Ptr, Lifetime L)
bool MarkDestroyed(InterpState &S, CodePtr OpPC)
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to const storage.
bool Interpret(InterpState &S)
Interpreter entry point.
bool(*)(InterpState &, CodePtr &PC) PRESERVE_NONE InterpFn
bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, bool Fatal)
bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
static bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool IsCtorDtor=false)
The JSON file list parser is used to communicate input to InstallAPI.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isa(CodeGen::Address addr)
@ Success
Annotation was successful.
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.
U cast(CodeGen::Address addr)
Describes a memory block created by an allocation site.
unsigned getNumElems() const
Returns the number of elements stored in the block.
bool isPrimitive() const
Checks if the descriptor is of a primitive.
bool hasTrivialDtor() const
Whether variables of this descriptor need their destructor called or not.
bool isCompositeArray() const
Checks if the descriptor is of an array of composites.
const ValueDecl * asValueDecl() const
const Decl * asDecl() const
const Descriptor *const ElemDesc
Descriptor of the array element.
unsigned getMetadataSize() const
Returns the size of the metadata.
SourceLocation getLocation() const
QualType getDataType(const ASTContext &Ctx) const
unsigned getElemDataSize() const
Returns the element data size, i.e.
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
const VarDecl * asVarDecl() const
PrimType getPrimType() const
bool isRecord() const
Checks if the descriptor is of a record.
const Record *const ElemRecord
Pointer to the record, if block contains records.
const Expr * asExpr() const
bool isArray() const
Checks if the descriptor is of an array.
Descriptor used for global variables.
Inline descriptor embedded in structures and arrays.
std::optional< IntPointer > atOffset(const ASTContext &ASTCtx, unsigned Offset) const