26#include "llvm/ADT/ScopeExit.h"
27#include "llvm/ADT/StringExtras.h"
32#if __has_cpp_attribute(clang::musttail)
33#define MUSTTAIL [[clang::musttail]]
34#elif __has_cpp_attribute(msvc::musttail)
35#define MUSTTAIL [[msvc::musttail]]
36#elif __has_attribute(musttail)
37#define MUSTTAIL __attribute__((musttail))
44#if defined(_MSC_VER) || defined(__powerpc__) || !defined(MUSTTAIL) || \
45 defined(__i386__) || defined(__sparc__)
48#define USE_TAILCALLS 0
50#define USE_TAILCALLS 1
54 llvm::report_fatal_error(
"Interpreter cannot return values");
85 S.
FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;
121 S.
FFDiag(Loc, diag::note_constexpr_access_unknown_variable, 1)
123 S.
Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();
125 S.
FFDiag(Loc, diag::note_constexpr_function_param_value_unknown, 1) << D;
135 }
else if (
const auto *VD = dyn_cast<VarDecl>(D)) {
136 if (!VD->getAnyInitializer()) {
140 S.
FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
141 S.
Note(VD->getLocation(), diag::note_declared_at);
163 if (
const auto *VarD = dyn_cast<VarDecl>(VD);
164 VarD && VarD->isCXXForRangeImplicitVar()) {
166 diag::note_constexpr_ltor_for_range_var)
171 if (
const auto *VarD = dyn_cast<VarDecl>(VD);
172 VarD && VarD->getType().isConstQualified() &&
173 (VarD->isConstexpr() || !VarD->getType()->isArrayType()) &&
174 !VarD->getAnyInitializer()) {
187 S.
FFDiag(Loc, diag::note_constexpr_modify_global);
189 S.
FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;
196 S.
getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr
197 : diag::note_constexpr_ltor_non_integral,
209 const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(
221 S.
FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
231 if (
auto ID = Ptr.getDeclID()) {
260 S.
CCEDiag(E, diag::note_constexpr_large_shift)
282 unsigned VariadicArgSize =
284 unsigned TargetStackSize = S.
Stk.
size() - VariadicArgSize;
285 while (S.
Stk.
size() != TargetStackSize) {
295 if (
Func->hasImplicitThisPointer())
318 if (Ptr.isFunctionPointer())
320 if (Ptr.isIntegralPointer())
322 if (Ptr.isTypeidPointer())
325 if (Ptr.getType()->isAnyComplexType())
328 if (
const Expr *
Base = Ptr.getRootExpr())
338 assert(Ptr.inUnion());
343 while (!
U.isRoot() && !
U.isActive()) {
348 if (
U.getRecord() &&
U.getRecord()->isAnonymousUnion())
355 assert(
C.getBase() ==
U);
369 if (!
U.getFieldDesc()->isUnion())
379 if (
const auto *CXXRD = dyn_cast<CXXRecordDecl>(R->getDecl());
380 CXXRD && !CXXRD->hasTrivialDefaultConstructor()) {
392 assert(!
C.isActive());
393 const FieldDecl *InactiveField =
C.getField();
394 assert(InactiveField);
397 const Record *R =
U.getRecord();
398 assert(R && R->isUnion() &&
"Not a union");
401 for (
const Record::Field &F : R->fields()) {
402 PtrView Field =
U.atField(F.Offset);
403 if (Field.isActive()) {
404 ActiveField = Field.getField();
410 diag::note_constexpr_access_inactive_union_member)
411 << AK << InactiveField << !ActiveField << ActiveField;
419 if (!Ptr.isPastEnd() &&
420 (Ptr.isInitialized() ||
428 const auto *VD = Ptr.getDeclDesc()->asValueDecl();
435 if (!Ptr.isUnknownSizeArray())
438 S.
FFDiag(E, diag::note_constexpr_unsized_array_indexed);
450 S.
FFDiag(Src, diag::note_constexpr_access_null) << AK;
458 if (Ptr.isDynamic()) {
459 S.
FFDiag(Src, diag::note_constexpr_access_deleted_object) << AK;
461 S.
FFDiag(Src, diag::note_constexpr_access_uninit)
480 if (D->getType().isConstQualified())
494 if (
T->isIntegralOrEnumerationType()) {
506 ? diag::note_constexpr_ltor_non_constexpr
507 : diag::note_constexpr_ltor_non_integral,
510 S.
Note(D->getLocation(), diag::note_declared_at);
517 if (
T->isPointerOrReferenceType()) {
535 if (!Ptr.isStatic() || !Ptr.isBlockPointer())
537 if (!Ptr.getDeclID())
547 S.
FFDiag(Loc, diag::note_constexpr_null_subobject)
555 if (!Ptr.isElementPastEnd() && !Ptr.isZeroSizeArray())
558 S.
FFDiag(Loc, diag::note_constexpr_past_end_subobject)
565 if (!Ptr.isOnePastEnd())
569 S.
FFDiag(Loc, diag::note_constexpr_past_end_subobject)
576 uint32_t MinOffset = Ptr.block()->getMetadataSize();
577 uint32_t PtrOffset = Ptr.getByteOffset();
581 if (Offset < PtrOffset && (PtrOffset - Offset) >= MinOffset)
590 QualType MostDerivedQT = Ptr.getDeclPtr().getType();
595 S.
CCEDiag(E, diag::note_constexpr_invalid_downcast)
596 << MostDerivedQT << TargetQT;
602 assert(Ptr.isLive() &&
"Pointer is not live");
606 if (Ptr.isMutable() && !Ptr.isConstInMutable())
609 if (!Ptr.isBlockPointer())
615 if (
V.block() != Ptr.block())
617 if (!
V.getFieldDesc()->IsConst) {
632 bool FoundProblem =
false;
633 for (
PtrView P = Ptr.view(); P !=
V; P = P.getBase()) {
634 if (P.getFieldDesc()->IsConst) {
650 if (!Ptr.getFieldDesc()->IsConst)
653 S.
FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
659 assert(Ptr.isLive() &&
"Pointer is not live");
660 if (!Ptr.isMutable())
676 MutablePtr = MutablePtr.
getBase();
680 S.
FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK << Field;
681 S.
Note(Field->getLocation(), diag::note_declared_at);
687 assert(Ptr.isLive());
689 if (!Ptr.isVolatile())
713 Loc = F->getLocation();
717 Loc = VD->getLocation();
722 Loc = E->getExprLoc();
726 diag::note_constexpr_access_volatile_obj, 1)
727 << AK << DiagKind << ND;
728 S.
Note(Loc, diag::note_constexpr_volatile_here) << DiagKind;
734 assert(Ptr.isLive());
735 assert(!Ptr.isInitialized());
737 Ptr.getLifetime(), AK);
755 VD && (VD->isConstexpr() || VD->hasGlobalStorage())) {
758 !(S.
getLangOpts().CPlusPlus23 && VD->getType()->isReferenceType())) {
767 S.
Note(VD->getFirstDecl()->getLocation(), diag::note_declared_at);
772 if (VD->getAnyInitializer()) {
774 S.
FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
775 S.
Note(VD->getLocation(), diag::note_declared_at);
805 return CheckLifetime(S, OpPC, Ptr.getLifetime(), Ptr.block(), AK);
816 S.
Note(VD->getLocation(), diag::note_declared_at);
847 diag::note_constexpr_access_volatile_obj, 1)
860 if (!Desc.IsInitialized)
870 diag::note_constexpr_access_volatile_obj, 1)
895 S.
FFDiag(Src, diag::note_constexpr_access_null) << AK;
899 if (!Ptr.isReadablePointerType())
902 if (Ptr.isBlockPointer() && !Ptr.block()->isAccessible()) {
918 if (!Ptr.isInitialized())
922 if (Ptr.isBlockPointer() && !
CheckTemporary(S, OpPC, Ptr.block(), AK))
932 if (Ptr.isBlockPointer() && !Ptr.isArrayRoot()) {
947 if (
const auto *CLE =
948 dyn_cast_if_present<CompoundLiteralExpr>(Desc->
asExpr())) {
949 if (
QualType CLETy = CLE->getType();
952 diag::note_invalid_subexpr_in_const_expr)
954 S.
Note(CLE->getExprLoc(), diag::note_declared_at);
965 assert(!Ptr.isZero());
966 if (!Ptr.isReadablePointerType())
969 if (Ptr.isBlockPointer() && !Ptr.block()->isAccessible()) {
986 if (!Ptr.isInitialized())
992 if (Ptr.isConstexprUnknown())
998 bool WillBeActivated) {
999 if (!Ptr.isBlockPointer() || Ptr.isZero())
1002 if (!Ptr.block()->isAccessible()) {
1029 bool IsCtor,
bool IsDtor) {
1061 StringRef Name = DiagDecl->
getName();
1063 Name ==
"__assert_rtn" || Name ==
"__assert_fail" || Name ==
"_wassert";
1066 diag::note_constexpr_assert_failed);
1073 diag::note_invalid_subexpr_in_const_expr);
1079 const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
1080 if (CD && CD->isInheritingConstructor()) {
1081 const auto *Inherited = CD->getInheritedConstructor().getConstructor();
1082 if (!Inherited->isConstexpr())
1083 DiagDecl = CD = Inherited;
1088 if (CD && CD->getParent()->isInvalidDecl())
1094 if (CD && CD->isInheritingConstructor()) {
1097 << CD->getInheritedConstructor().getConstructor()->getParent();
1105 if (!IsDefined && !IsExtern && DiagDecl->
isConstexpr() &&
1115 diag::note_constexpr_invalid_function, 1)
1116 << DiagDecl->
isConstexpr() << (bool)CD << DiagDecl;
1132 S.
CCEDiag(Loc, diag::note_constexpr_virtual_call);
1156 diag::note_constexpr_depth_limit_exceeded)
1170 bool IsImplicit =
false;
1171 if (
const auto *TE = dyn_cast<CXXThisExpr>(E))
1172 IsImplicit = TE->isImplicit();
1173 S.
FFDiag(E, diag::note_constexpr_this) << IsImplicit;
1188 if ((Status & APFloat::opInexact) &&
1193 S.
FFDiag(E, diag::note_constexpr_dynamic_rounding);
1197 if ((Status != APFloat::opOK) &&
1200 FPO.getAllowFEnvAccess())) {
1202 S.
FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
1206 if ((Status & APFloat::opStatus::opInvalidOp) &&
1218 APFloat::opStatus Status,
FPOptions FPO) {
1229 S.
CCEDiag(E, diag::note_constexpr_float_arithmetic)
1242 S.
CCEDiag(E, diag::note_constexpr_new);
1249 const Expr *NewExpr) {
1250 if (AllocForm == DeleteForm)
1256 S.
FFDiag(E, diag::note_constexpr_new_delete_mismatch)
1257 <<
static_cast<int>(DeleteForm) <<
static_cast<int>(AllocForm)
1259 S.
Note(NewExpr->
getExprLoc(), diag::note_constexpr_dynamic_alloc_here)
1267 if (isa_and_nonnull<CXXNewExpr>(Source))
1270 if (
const auto *CE = dyn_cast_if_present<CallExpr>(Source);
1271 CE && CE->getBuiltinCallee() == Builtin::BI__builtin_operator_new)
1274 if (
const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(Source);
1275 MCE && MCE->getMethodDecl()->
getIdentifier()->isStr(
"allocate"))
1280 S.
FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)
1300 S.
FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
1301 S.
Note(VD->getLocation(), diag::note_declared_at);
1321 S.
FFDiag(E, diag::note_constexpr_modify_global);
1327 const CallExpr *CE,
unsigned ArgSize) {
1330 unsigned Offset = 0;
1332 for (
const Expr *Arg : Args) {
1333 if (NonNullArgs[Index] && Arg->getType()->isPointerType()) {
1337 S.
CCEDiag(Loc, diag::note_non_null_attribute_failed);
1359 S.
FFDiag(Loc, diag::note_constexpr_double_destroy);
1366 assert(!
Dtor->isTrivial());
1372 return Call(S, OpPC, DtorFunc, 0);
1395 for (
int I =
static_cast<int>(N) - 1; I >= 0; --I) {
1409 return DD->isVirtual();
1414 bool IsGlobalDelete) {
1420 const Expr *Source =
nullptr;
1421 const Block *BlockToDelete =
nullptr;
1431 if (!Ptr.isBlockPointer())
1435 QualType InitialType = Ptr.getType();
1436 Ptr = Ptr.expand().stripBaseCasts();
1438 Source = Ptr.getRootExpr();
1439 BlockToDelete = Ptr.block();
1443 if (std::optional<DynamicAllocator::Form> AllocForm =
1455 if (!DeleteIsArrayForm && Ptr.getType() != InitialType &&
1458 diag::note_constexpr_delete_base_nonvirt_dtor)
1459 << InitialType << Ptr.getType();
1463 if (!Ptr.isRoot() || (Ptr.isOnePastEnd() && !Ptr.isZeroSizeArray()) ||
1464 (Ptr.isArrayElement() && Ptr.getIndex() != 0)) {
1466 S.
FFDiag(Loc, diag::note_constexpr_delete_subobject)
1467 << Ptr.toDiagnosticString(S.
getASTContext()) << Ptr.isOnePastEnd();
1476 if (!DeleteIsArrayForm && !IsGlobalDelete) {
1477 QualType AllocType = Ptr.getType();
1481 return DD->isVirtual() ? DD->getOperatorDelete() :
nullptr;
1491 diag::note_constexpr_new_non_replaceable)
1498 assert(BlockToDelete);
1504 if (!Allocator.
deallocate(Source, BlockToDelete)) {
1507 S.
FFDiag(Loc, diag::note_constexpr_double_delete);
1524 S.
CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)
1525 << llvm::toString(
Value, 10) <<
Min.getSExtValue() <<
Max.getSExtValue()
1529 S.
CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)
1530 << llvm::toString(
Value, 10) <<
Min.getZExtValue() <<
Max.getZExtValue()
1561 S.
FFDiag(E, diag::note_constexpr_nonliteral) << E->
getType();
1563 S.
FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
1568 const Pointer &Ptr,
unsigned Offset) {
1569 assert(Ptr.isTypeidPointer());
1571 Ptr.asTypeidPointer().TypeInfoType->getAsRecordDecl());
1574 const Record::Field *Field = R->findField(Offset);
1578 std::string TypeIdStr;
1579 llvm::raw_string_ostream SS(TypeIdStr);
1581 QualType(Ptr.asTypeidPointer().TypePtr, 0)
1584 SS << Field->Decl->getNameAsString();
1587 diag::note_constexpr_access_unreadable_object)
1594 diag::note_constexpr_null_subobject);
1610 if (Ptr.isIntegralPointer()) {
1611 if (std::optional<IntPointer> IntPtr =
1612 Ptr.asIntPointer().atOffset(S.
Ctx,
Off)) {
1619 if (Ptr.isOpaquePointer()) {
1628 const Record::Field *F = R->findField(
Off);
1636 F->Decl->getType().getTypePtr()),
1637 Ptr.getByteOffset());
1642 if (!Ptr.isBlockPointer()) {
1645 if (Ptr.isTypeidPointer())
1651 if (!Ptr.getFieldDesc()->isRecord())
1654 if ((Ptr.getByteOffset() +
Off) >= Ptr.block()->getSize())
1672 uint32_t
Off,
bool NullOK) {
1676 if (Ptr.isOpaquePointer()) {
1684 const Record::Base *B = R->findBase(
Off);
1695 Ptr.getByteOffset());
1699 if (!Ptr.isBlockPointer()) {
1700 if (!Ptr.isIntegralPointer())
1711 if (!Ptr.getFieldDesc()->isRecord()) {
1725 return getBase(S, OpPC, Ptr.narrow(),
Off,
true);
1729 return getBase(S, OpPC, Ptr.narrow(),
Off, NullOK);
1733 const Type *TargetType) {
1738 if (!Ptr.isBlockPointer()) {
1746 if (!Ptr.getFieldDesc()->isRecord()) {
1756 const Record *TargetRecord = Ptr.atFieldSub(
Off).getRecord();
1757 assert(TargetRecord);
1761 QualType MostDerivedType = Ptr.getDeclDesc()->getType();
1763 << MostDerivedType <<
QualType(TargetType, 0);
1773 assert(
Func->isConstructor());
1775 if (
Func->getParentDecl()->isInvalidDecl())
1791 <<
Func->getParentDecl();
1799 if (
const Decl *D = Ptr.getDeclDesc()->asDecl()) {
1801 S.
FFDiag(ND->getLocation(), diag::note_constexpr_destroy_out_of_lifetime)
1802 << ND->getNameAsString();
1804 S.
FFDiag(Ptr.getDeclDesc()->getLocation(),
1805 diag::note_constexpr_destroy_out_of_lifetime)
1830 if (Ptr.block()->isStatic()) {
1832 S.
FFDiag(E, diag::note_constexpr_modify_global);
1855 bool SrcIsVoidPtr) {
1859 if (!Ptr.isBlockPointer())
1866 bool HasValidResult = !Ptr.isZero();
1868 if (HasValidResult) {
1878 S.
CCEDiag(E, diag::note_constexpr_invalid_void_star_cast)
1879 << E->getSubExpr()->getType() << S.
getLangOpts().CPlusPlus26
1880 << Ptr.getType().getCanonicalType() << E->getType()->getPointeeType();
1883 S.
CCEDiag(E, diag::note_constexpr_invalid_cast)
1884 << diag::ConstexprInvalidCastKind::CastFrom <<
"'void *'"
1893 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
1911 uint32_t VarArgSize) {
1912 if (
Func->hasThisPointer()) {
1913 size_t ArgSize =
Func->getArgSize() + VarArgSize;
1923 Func->isLambdaCallOperator())) {
1925 Func->isDestructor()))
1933 if (!
Func->isFullyCompiled())
1949 assert(S.
Current == FrameBefore);
1961 uint32_t VarArgSize) {
1968 auto cleanup = [&]() ->
bool {
1973 bool InstancePtrTracked =
false;
1974 if (
Func->hasThisPointer()) {
1975 size_t ArgSize =
Func->getArgSize() + VarArgSize;
1992 Func->isLambdaCallOperator()) {
1993 assert(ThisPtr.
isZero());
1996 Func->isDestructor()))
1999 if (
Func->isCopyOrMoveOperator() ||
Func->isCopyOrMoveConstructor()) {
2006 if (!
Func->isConstructor() && !
Func->isDestructor() &&
2016 InstancePtrTracked = (
Func->isConstructor() ||
Func->isDestructor());
2017 if (InstancePtrTracked)
2021 if (!
Func->isFullyCompiled())
2044 if (InstancePtrTracked)
2055 assert(S.
Current == FrameBefore);
2065 auto depth = [](
PtrView V) ->
unsigned {
2067 while (!
V.isRoot()) {
2084 assert(depth(TypePtr) >= depth(InitPtr));
2085 unsigned D = depth(TypePtr) - depth(InitPtr);
2086 for (
unsigned I = 0; I != D; ++I)
2097 S.
FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
2104 DynamicDecl =
DynamicType->getPointeeCXXRecordDecl();
2112 return DynamicDecl !=
nullptr;
2116struct DynamicCastResult {
2120 bool valid()
const {
return !
Ambiguous && Offset; }
2122 void setOffset(
unsigned O) {
2130 void merge(DynamicCastResult
C) {
2131 Ambiguous |=
C.Ambiguous;
2145 DynamicCastResult Res;
2150 for (
const Record::Base &B : R->bases()) {
2153 N.Offset = *N.Offset + B.Offset;
2161 bool IsReferenceCast) {
2165 if (Ptr.isConstexprUnknown()) {
2170 S.
FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
2175 if (!Ptr.isBlockPointer() || !Ptr.getRecord())
2178 if (!Ptr.isInitialized())
2186 LimitedPtr = Ptr.stripBaseCasts().view();
2189 assert(LimitedPtr.
block() == Ptr.block());
2196 if (TargetType->isVoidType()) {
2201 assert(!TargetType.isNull());
2202 assert(!TargetType->isVoidType());
2203 assert(TargetType->isRecordType());
2210 assert(P.getRecord());
2214 auto baseIsPrivate = [&](
PtrView P) ->
bool {
2215 if (P.isRoot() || !P.isBaseClass())
2219 getRecord(P.getBase())->isDerivedFrom(getRecord(P), Paths);
2224 return llvm::all_of(Paths, [](
const CXXBasePath &P) ->
bool {
2230 DiagPrivateBase = 0,
2233 DiagPrivateSibling = 3
2236 auto diag = [&](
int DiagKind,
QualType ResultType) ->
bool {
2238 if (!IsReferenceCast) {
2244 diag::note_constexpr_dynamic_cast_to_reference_failed)
2245 << DiagKind << ResultType <<
DynamicType << TargetType;
2254 getRecord(LimitedPtr)
2255 ->isDerivedFrom(TargetType->getAsCXXRecordDecl(), Paths);
2256 if (std::distance(Paths.
begin(), Paths.
end()) == 0 &&
2257 !typesMatch(LimitedPtr.
getType(), TargetType)) {
2258 return diag(DiagNoBase, TargetType);
2263 if (baseIsPrivate(Ptr.view()))
2264 return diag(DiagPrivateBase, Ptr.getType());
2266 std::optional<PtrView>
Result;
2268 for (
PtrView Iter = Ptr.view();;) {
2269 if (Iter.isRoot() || !Iter.isBaseClass())
2272 if (typesMatch(TargetType, Iter.getType())) {
2277 Iter = Iter.getBase();
2283 if (baseIsPrivate(*
Result))
2284 return diag(DiagPrivateBase,
Result->getType());
2291 for (
PtrView Iter = LimitedPtr;;) {
2297 Result = Iter.atField(*R.Offset);
2305 if (Iter.isRoot() || !Iter.isBaseClass())
2308 Iter = Iter.getBase();
2312 return diag(DiagAmbiguous, TargetType);
2316 if (baseIsPrivate(*
Result))
2317 return diag(DiagPrivateSibling, TargetType);
2323 return diag(DiagNoBase, TargetType);
2327 uint32_t VarArgSize) {
2328 assert(
Func->hasThisPointer());
2329 assert(
Func->isVirtual());
2330 size_t ArgSize =
Func->getArgSize() + VarArgSize;
2342 assert(DynamicDecl);
2344 const auto *StaticDecl =
Func->getParentDecl();
2348 if (StaticDecl != DynamicDecl) {
2355 Overrider = InitialFunction;
2365 S.
Note(Callee->getLocation(), diag::note_declared_at);
2369 if (Overrider != InitialFunction) {
2382 if (
Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
2390 if (!
Call(S, OpPC,
Func, VarArgSize))
2395 if (Overrider != InitialFunction &&
2397 InitialFunction->getReturnType()->isPointerOrReferenceType()) {
2405 OverriderPointeeType))
2422 uint32_t BuiltinID) {
2425 if (BuiltinID == Builtin::BI__builtin_operator_new &&
2442 if (!Ptr.isFunctionPointer())
2445 const Function *F = Ptr.asFunctionPointer().Func;
2489 return CallVirt(S, OpPC, F, VarArgSize);
2491 return Call(S, OpPC, F, VarArgSize);
2495 if (
const Record *R = Ptr.getRecord()) {
2496 Ptr.startLifetime();
2498 for (
const Record::Field &Fi : R->fields()) {
2499 PtrView FP = Ptr.atField(Fi.Offset);
2506 if (
const Descriptor *FieldDesc = Ptr.getFieldDesc();
2507 FieldDesc->isCompositeArray()) {
2508 for (
unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
2509 PtrView EP = Ptr.atIndex(I).narrow();
2516 Ptr.startLifetime();
2524 if (!Ptr.isBlockPointer())
2535 if (!Ptr.isBlockPointer())
2537 Ptr.startLifetime();
2544 if (
const Record *R = Ptr.getRecord()) {
2545 Ptr.setLifeState(L);
2546 for (
const Record::Field &Fi : R->fields())
2551 if (
const Descriptor *FieldDesc = Ptr.getFieldDesc();
2552 FieldDesc->isCompositeArray()) {
2554 if (Ptr.getFieldDesc()->isPrimitiveArray())
2556 for (
unsigned I = 0; I != FieldDesc->getNumElems(); ++I)
2561 Ptr.setLifeState(L);
2593 std::optional<uint64_t> ArraySize) {
2597 auto directBaseIsUnion = [](
const Pointer &Ptr) ->
bool {
2598 if (Ptr.isArrayElement())
2600 const Record *R = Ptr.getBase().getRecord();
2601 return R && R->isUnion();
2604 if (Ptr.inUnion() && directBaseIsUnion(Ptr))
2613 if (!Ptr.isBlockPointer())
2623 if (!Ptr.block()->isAccessible()) {
2634 for (
PtrView P = Ptr.view();;) {
2657 QualType StorageType = Ptr.getType();
2661 NewExpr->getAllocatedType(),
2662 APInt(64,
static_cast<uint64_t
>(*ArraySize),
false),
nullptr,
2665 AllocType = NewExpr->getAllocatedType();
2668 if (AllocType->
isArrayType() && Ptr.isArrayElement() &&
2669 Ptr.expand().getIndex() == 0) {
2677 StorageType = Ptr.expand().getArray().getType();
2684 diag::note_constexpr_placement_new_wrong_type)
2685 << StorageType << AllocType;
2690 if (Ptr.inUnion() && !Ptr.isActive() && !directBaseIsUnion(Ptr))
2699 if (
const auto *NewExpr = dyn_cast<CXXNewExpr>(E)) {
2700 const FunctionDecl *OperatorNew = NewExpr->getOperatorNew();
2702 if (NewExpr->getNumPlacementArgs() > 0) {
2713 ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
2715 diag::note_constexpr_new_non_replaceable)
2719 NewExpr->getNumPlacementArgs() == 1 &&
2720 !OperatorNew->isReservedGlobalPlacementOperator()) {
2730 const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelete();
2732 ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
2734 diag::note_constexpr_new_non_replaceable)
2748 E->
getExprLoc(), diag::warn_fixedpoint_constant_overflow)
2751 S.
CCEDiag(E, diag::note_constexpr_overflow)
2759 diag::err_shufflevector_minus_one_is_undefined_behavior_constexpr)
2765 const Pointer &Ptr,
unsigned BitWidth) {
2768 S.
CCEDiag(E, diag::note_constexpr_invalid_cast_ptrtoint)
2769 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
2771 if (Ptr.isBlockPointer() && !Ptr.isZero())
2773 if (Ptr.isIntegralPointer())
2776 if (Ptr.isDummy()) {
2779 return Ptr.getIndex() == 0;
2782 if (!Ptr.isZero()) {
2802 Result.copy(
APInt(BitWidth, Ptr.getIntegerRepresentation()));
2815 Result.copy(
APInt(BitWidth, Ptr.getIntegerRepresentation()));
2822 bool TargetIsUCharOrByte) {
2824 if (!HasIndeterminateBits)
2828 if (TargetIsUCharOrByte)
2833 S.
FFDiag(E, diag::note_constexpr_bit_cast_indet_dest)
2845 if (!ID.IsInitialized) {
2848 diag::note_constexpr_use_uninit_reference);
2865 if (!P.isBlockPointer())
2868 if (P.isConstexprUnknown()) {
2873 S.
FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
2879 CanQualType T = P.stripBaseCasts().getType()->getCanonicalTypeUnqualified();
2885 Func && (
Func->isConstructor() ||
Func->isDestructor()) &&
2886 P.block() ==
Frame->getThis().block()) {
2888 Func->getParentDecl());
2900 S.
CCEDiag(E, diag::note_constexpr_typeid_polymorphic)
2901 << E->getExprOperand()->getType()
2902 << E->getExprOperand()->getSourceRange();
2916 StringRef LHSStr(LHSLit->getBytes());
2917 unsigned LHSLength = LHSStr.size();
2918 StringRef RHSStr(RHSLit->getBytes());
2919 unsigned RHSLength = RHSStr.size();
2921 int32_t IndexDiff = RHSOffset - LHSOffset;
2922 if (IndexDiff < 0) {
2923 if (
static_cast<int32_t
>(LHSLength) < -IndexDiff)
2925 LHSStr = LHSStr.drop_front(-IndexDiff);
2927 if (
static_cast<int32_t
>(RHSLength) < IndexDiff)
2929 RHSStr = RHSStr.drop_front(IndexDiff);
2932 unsigned ShorterCharWidth;
2935 if (LHSLength < RHSLength) {
2936 ShorterCharWidth = LHSLit->getCharByteWidth();
2940 ShorterCharWidth = RHSLit->getCharByteWidth();
2948 for (
unsigned NullByte : llvm::seq(ShorterCharWidth)) {
2949 if (Shorter.size() + NullByte >= Longer.size())
2951 if (Longer[Shorter.size() + NullByte])
2954 return Shorter == Longer.take_front(Shorter.size());
2960 if (!Val.singleWord()) {
2961 uint64_t *NewMemory =
new (S.
P) uint64_t[Val.numWords()];
2962 Val.take(NewMemory);
2966 if (!Val.singleWord()) {
2967 uint64_t *NewMemory =
new (S.
P) uint64_t[Val.numWords()];
2968 Val.take(NewMemory);
2972 if (!Val.singleWord()) {
2973 uint64_t *NewMemory =
new (S.
P) uint64_t[Val.numWords()];
2974 Val.take(NewMemory);
2980 std::copy_n(Val.path(), PathLength, NewPath);
2981 Val.takePath(NewPath);
2985template <
typename T>
2988 if constexpr (std::is_same_v<T, MemberPointer>) {
2992 std::copy_n(Val.path(), PathLength, NewPath);
2993 Val.takePath(NewPath);
2995 auto &Val = Ptr.deref<
T>();
2996 if (!Val.singleWord()) {
2997 uint64_t *NewMemory =
new (S.
P) uint64_t[Val.numWords()];
2998 Val.take(NewMemory);
3004 if (
const Record *R = Ptr.getRecord()) {
3005 for (
const Record::Field &Fi : R->fields()) {
3006 if (Fi.Desc->isPrimitive()) {
3008 copyPrimitiveMemory<T>(S, Ptr.atField(Fi.Offset));
3017 if (
const Descriptor *D = Ptr.getFieldDesc(); D && D->isArray()) {
3018 unsigned NumElems = D->getNumElems();
3022 if (D->isPrimitiveArray()) {
3026 assert(NumElems >= 1);
3028 bool AllSingleWord =
true;
3030 if (!EP.
deref<
T>().singleWord()) {
3032 AllSingleWord =
false;
3037 for (
unsigned I = 1; I != D->getNumElems(); ++I) {
3042 assert(D->isCompositeArray());
3043 for (
unsigned I = 0; I != D->getNumElems(); ++I) {
3044 PtrView EP = Ptr.atIndex(I).narrow();
3055 if (Ptr.canBeInitialized()) {
3068 S.
CCEDiag(Loc, diag::note_constexpr_invalid_cast)
3069 << diag::ConstexprInvalidCastKind::Reinterpret
3078 S.
CCEDiag(Loc, diag::note_constexpr_invalid_cast)
3079 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
3086 S.
FFDiag(E, diag::note_constexpr_access_volatile_type)
3087 <<
AK_Read << E->getSubExpr()->getType();
3095 S.
CCEDiag(Loc, diag::note_constexpr_invalid_cast)
3096 << diag::ConstexprInvalidCastKind::Dynamic;
3099 llvm_unreachable(
"Unhandled CastKind");
3132 if (MemberPtr.getPathLength() >= 2)
3133 Expected = MemberPtr.getPathEntry(MemberPtr.getPathLength() - 2);
3135 Expected = MemberPtr.getRecordDecl();
3148 unsigned OldPathLength = MemberPtr.getPathLength();
3149 unsigned NewPathLength = OldPathLength - 1;
3150 bool IsDerivedMember = NewPathLength != 0;
3152 std::copy_n(MemberPtr.path(), NewPathLength, NewPath);
3155 NewPath, IsDerivedMember));
3163 bool IsDerivedMember) {
3164 unsigned OldPathLength = MemberPtr.getPathLength();
3165 unsigned NewPathLength = OldPathLength + 1;
3168 std::copy_n(MemberPtr.path(), OldPathLength, NewPath);
3172 NewPath, IsDerivedMember));
3181 if (!Ptr.isDerivedMember() && Ptr.hasPath())
3184 bool IsDerivedMember = Ptr.isDerivedMember() || !Ptr.hasPath();
3193 if (!Ptr.isDerivedMember()) {
3210 if (!MP.isBaseCastPossible())
3221 const auto *FD = dyn_cast_if_present<FunctionDecl>(D);
3225 const auto *
Method = dyn_cast<CXXMethodDecl>(FD);
3232 if (!
Base.getRecord() ||
Base.getRecord()->getDecl() != MethodParent)
3249 unsigned NewPathLength = OldPathLength + 1;
3252 std::copy_n(MemberPtr.path(), OldPathLength, NewPath);
3256 MemberPtr.withPath(NewPathLength, NewPath, IsDerived));
3260template <
bool Signed>
3262 uint32_t BitWidth, uint32_t FPOI) {
3267 if ((Status & APFloat::opStatus::opInvalidOp) && F.
isFinite() &&
3300 APSInt &&Index,
bool AllowReplace) {
3309 ElemType = AT->getElementType();
3314 unsigned NewPathLength;
3325 if (Index.isNonNegative())
3334 Ptr.getByteOffset());
3341 size_t NewOffset = Ptr.getByteOffset() + (Index.getZExtValue() * ElemSize);
3342 bool PastEnd = Index != 0;
3353 assert(Ptr.isOpaquePointer());
3354 if (Offset.isZero())
3360 unsigned NumElems = 1;
3362 ElemTy = AT->getElementType();
3363 if (
const auto *CAT = dyn_cast<ConstantArrayType>(AT))
3364 NumElems = CAT->getZExtSize();
3369 S.
FFDiag(E, diag::note_constexpr_unsized_array_indexed);
3370 return std::nullopt;
3373 if (Offset > NumElems) {
3384 return std::nullopt;
3387 if (Offset.getActiveBits() > 64)
3388 return std::nullopt;
3396 NewPath[NewPathLength - 1].
Index += Offset.getZExtValue();
3398 NewPath[NewPathLength - 1].
Index -= Offset.getZExtValue();
3406 NewOffset = Ptr.getByteOffset() + (ElemSize * Offset.getZExtValue());
3408 NewOffset = Ptr.getByteOffset() - (ElemSize * Offset.getZExtValue());
3417 return Op == OP_RetVoid || Op == OP_RetValue || Op == OP_NoRet ||
3418 Op == OP_RetSint8 || Op == OP_RetUint8 || Op == OP_RetSint16 ||
3419 Op == OP_RetUint16 || Op == OP_RetSint32 || Op == OP_RetUint32 ||
3420 Op == OP_RetSint64 || Op == OP_RetUint64 || Op == OP_RetIntAP ||
3421 Op == OP_RetIntAPS || Op == OP_RetBool || Op == OP_RetFixedPoint ||
3422 Op == OP_RetPtr || Op == OP_RetMemberPtr || Op == OP_RetFloat ||
3423 Op == OP_EndSpeculation;
3432#define GET_INTERPFN_DISPATCHERS
3433#include "Opcodes.inc"
3434#undef GET_INTERPFN_DISPATCHERS
3439#define GET_INTERPFN_LIST
3440#include "Opcodes.inc"
3441#undef GET_INTERPFN_LIST
3463 return InterpNext(S);
3491 [[maybe_unused]]
CodePtr PCBefore = S.
PC;
3492 size_t StackSizeBefore = S.
Stk.
size();
3498 assert(DepthBefore >= 1);
3501 auto SpeculativeInterp = [&S]() ->
bool {
3524 if (SpeculativeInterp()) {
3529 assert(S.
Stk.
size() == StackSizeBefore);
3535 assert(S.
Stk.
size() == StackSizeBefore);
Defines the clang::ASTContext interface.
Defines the clang::Expr interface and subclasses for C++ expressions.
static const FunctionDecl * getVirtualOperatorDelete(QualType T)
static PRESERVE_NONE bool RetValue(InterpState &S)
static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK)
static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
static bool Jf(InterpState &S, CodePtr OpPC, int32_t Offset)
static bool Jmp(InterpState &S, CodePtr OpPC, int32_t Offset)
static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC, const ValueDecl *D, AccessKinds AK=AK_Read)
static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, const ValueDecl *VD, AccessKinds AK=AK_Read)
static bool isModification(AccessKinds AK)
static void noteValueLocation(InterpState &S, const Block *B)
static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC, const ValueDecl *VD)
static bool Jt(InterpState &S, CodePtr OpPC, int32_t Offset)
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.
static bool hasLayout(const RecordDecl *D)
Whether layout (offset and size) information can be queried for D.
const clang::PrintingPolicy & getPrintingPolicy() const
const ArrayType * getAsArrayType(QualType T) const
Type Query functions.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
bool hasSimilarType(QualType T1, QualType T2) const
Determine if two types are similar, according to the C++ rules.
DiagnosticsEngine & getDiagnostics() const
const TargetInfo & getTargetInfo() const
CanQualType getCanonicalTagType(const TagDecl *TD) const
Represents an array type, per C99 6.7.5.2 - Array Declarators.
QualType getElementType() const
Represents a path from a specific derived class (which is not represented as part of the path) to a p...
AccessSpecifier Access
The access along this inheritance path.
BasePaths - Represents the set of paths from a derived class to one of its (direct or indirect) bases...
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.
const T * getTypePtr() const
Retrieve the underlying type pointer, which refers to a canonical type.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
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
static FPOptions getFromOpaqueInt(storage_type Value)
RoundingMode getRoundingMode() const
Represents a member of a struct/union/class.
Represents a function declaration or definition.
QualType getReturnType() const
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...
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.
void addConst()
Add the const type qualifier to this QualType.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
bool isConstQualified() const
Determine whether this type is const-qualified.
Represents a struct/union/class.
Encodes a location in the source.
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
CanQualType getCanonicalTypeUnqualified() 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.
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
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.
bool isStaticDataMember() const
Determines whether this is a static data member.
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.
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 Record * getRecord(const RecordDecl *D) 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.
std::optional< Form > getAllocationForm(const Expr *Source) const
Checks whether the allocation done at the given source is an array allocation.
bool deallocate(const Expr *Source, const Block *BlockToDelete)
Deallocate the given source+block combination.
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.
APFloat::opStatus convertToInteger(APSInt &Result) const
APFloat getAPFloat() const
Base class for stack frames, shared between VM and walker.
bool hasExplicitThisPointer() const
Scope & getScope(unsigned Idx)
Returns a specific scope.
CodePtr getCodeBegin() const
Returns a pointer to the start of the code.
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.
unsigned getWrittenArgSize() const
unsigned getArgSize() const
Returns the size of the argument stack.
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.
void copy(const APInt &V)
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.
SourceLocation getLocation(CodePtr PC) const
static void free(InterpFrame *F)
InterpFrame * Caller
The frame of the previous function.
SourceInfo getSource(CodePtr PC) const
Map a location to a source.
SourceRange getRange(CodePtr PC) const
Block * getLocalBlock(unsigned Offset) const
const Pointer & getThis() const
Returns the 'this' pointer.
unsigned MSVCConstexprAllowed
const Function * getFunction() const
Returns the current function.
bool isBottomFrame() const
unsigned getArgSize() 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.
const Expr * getExpr(CodePtr PC) const
unsigned getDepth() const
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.
bool lifetimeStartedInEvaluation(const Block *B) const
Context & getContext() const
bool initializingBlock(const Block *B) const
DynamicAllocator & getAllocator()
Context & Ctx
Interpreter Context.
const unsigned EvalID
ID identifying this evaluation.
bool noteStep(CodePtr OpPC)
Note that a step has been executed.
InterpStack & Stk
Temporary stack.
bool checkingConstantDestruction() const
Return if we're checking if a global variable has a constant destructor.
const VarDecl * EvaluatingDecl
Declaration we're initializing/evaluting, if any.
InterpFrame * Current
The current frame.
PointerPathEntry * allocPointerPath(unsigned Length, const PointerPathEntry *OldPP)
const CXXRecordDecl ** allocMemberPointerPath(unsigned Length)
void deallocate(Block *B)
Deallocates a pointer.
PointerPathEntry * extendPointerPath(unsigned NewLength, const PointerPathEntry *OldPP, PointerPathEntry NewEntry)
Allocate a new pointer path of Length NewLength.
llvm::SmallVector< PtrView > InitializingPtrs
List of blocks we're currently running either constructors or destructors for.
T allocAP(unsigned BitWidth)
unsigned SpeculationDepth
StdAllocatorCaller getStdAllocatorCaller(StringRef Name) const
bool inConstantContext() const
Program & P
Reference to the module containing all bytecode.
unsigned getPathLength() const
Return the length of the cast path.
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.
Pointer stripBaseCasts() const
Strip base casts from this Pointer.
const Expr * getRootExpr() const
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
bool isDummy() const
Checks if the pointer points to a dummy value.
int64_t getIndex() const
Returns the index into an array.
bool isStringPointer() const
unsigned getNumElems() const
Returns the number of elements.
QualType getType() const
Returns the type of the innermost field.
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
bool isZero() const
Checks if the pointer is null.
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.
bool isOnePastEnd() const
Checks if the index is one past end.
const FieldDecl * getField() const
Returns the field information.
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
bool isBlockPointer() const
const Block * block() const
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
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.
SourceLocation getLoc() const
bool checkingForUndefinedBehavior() const
Are we checking an expression for overflow?
OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId)
Add a note to a prior diagnostic.
bool emitRelaxedDiag(SourceLocation Loc, diag::kind DiagId)
If DiagId should be relaxed as per the current evaluation settings, emit it as a warning instead of a...
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 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.
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.
static bool CheckCallDepth(InterpState &S, CodePtr OpPC)
static constexpr bool OpReturns(Opcode Op)
const InterpFn InterpFunctions[]
static bool diagnoseCallableDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *DiagDecl)
bool GetTypeid(InterpState &S, const Type *TypePtr, const Type *TypeInfoType)
Typeid support.
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 arrayElemPtrOpaque(InterpState &S, CodePtr OpPC, const Pointer &Ptr, APSInt &&Index, bool AllowReplace)
bool CheckFunctionDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *FD)
Opcode. Check if the function decl can be called at compile time.
std::optional< Pointer > addSubOffsetOpaque(InterpState &S, CodePtr OpPC, const Pointer &Ptr, APSInt &&Offset, ArithOp Op)
bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue)
static bool appendToMemberPointer(InterpState &S, const MemberPointer &MemberPtr, int32_t BaseOffset, const RecordDecl *BaseDecl, bool IsDerivedMember)
static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F)
bool StartThisLifetime(InterpState &S)
void cleanupAfterFunctionCall(InterpState &S, const Function *Func)
static bool runRecordDestructor(InterpState &S, CodePtr OpPC, const Pointer &BasePtr, const Descriptor *Desc)
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc, AccessKinds AK)
Checks if the Descriptor is of a constexpr or const global variable.
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.
static void setLifeStateRecurse(PtrView Ptr, Lifetime L)
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.
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.
static bool getDynamicDecl(InterpState &S, CodePtr OpPC, PtrView TypePtr, const CXXRecordDecl *&DynamicDecl)
bool CastMemberPtrDerivedPop(InterpState &S, int32_t Off, const RecordDecl *BaseDecl)
BaseToDerivedMemberPointer.
static DynamicCastResult findRecordBase(const ASTContext &Ctx, const Record *R, QualType Needle)
static bool CheckWeak(InterpState &S, CodePtr OpPC, const Block *B)
static void copyPrimitiveMemory(InterpState &S, PtrView Ptr, PrimType T)
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 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)
bool GetMemberPtrDecl(InterpState &S)
bool handleReference(InterpState &S, CodePtr OpPC, Block *B)
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.
static bool getField(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t Off)
static void startLifetimeRecurse(PtrView Ptr)
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)
static void finishGlobalRecurse(InterpState &S, PtrView Ptr)
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
bool CheckBCPResult(InterpState &S, const Pointer &Ptr)
PRESERVE_NONE bool EndSpeculation(InterpState &S)
bool diagnoseShiftFailure(InterpState &S, CodePtr OpPC, ShiftFailure Failure, const APSInt *Value, unsigned Bits)
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 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.
static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func, const Pointer &ThisPtr)
void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, const APSInt &Value)
bool isConstexprUnknown(const Block *B)
bool StartThisLifetime1(InterpState &S)
bool RVOPtr(InterpState &S)
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.
static bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool IsCtor, bool IsDtor)
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(*)(InterpState &) PRESERVE_NONE InterpFn
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)
static bool floatAPCast(InterpState &S, CodePtr OpPC, const Floating &F, uint32_t BitWidth, uint32_t FPOI)
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 checkDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T)
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
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 GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)
static void compileFunction(InterpState &S, const Function *Func)
bool CheckThis(InterpState &S, CodePtr OpPC)
Checks the 'this' pointer.
bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)
bool CheckIntegralAddressCast(InterpState &S, CodePtr OpPC, unsigned BitWidth)
bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I)
bool CheckMutable(InterpState &S, CodePtr OpPC, PtrView Ptr, AccessKinds AK)
Checks if a pointer points to a mutable field.
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.
static bool allowNullSubObj(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
bool FinishInitGlobal(InterpState &S)
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off, bool NullOK)
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)
bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)
bool MarkDestroyed(InterpState &S, CodePtr OpPC)
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
static bool validType(QualType T)
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 GetMemberPtr(InterpState &S, const ValueDecl *D)
static PRESERVE_NONE bool BCP(InterpState &S, CodePtr OpPC, int32_t Offset, PrimType PT)
This is used to implement speculative execution via __builtin_constant_p when we generate bytecode.
bool CastMemberPtrBasePop(InterpState &S, int32_t Off, const RecordDecl *BaseDecl)
DerivedToBaseMemberPointer.
bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, bool Fatal)
bool DynamicCast(InterpState &S, CodePtr OpPC, const Type *DestTypePtr, bool IsReferenceCast)
static bool diagnoseTypeIdField(InterpState &S, CodePtr OpPC, const Pointer &Ptr, unsigned Offset)
Top level wrappers for InstallAPI frontend operations.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isa(CodeGen::Address addr)
@ Ambiguous
Name lookup results in an ambiguity; use getAmbiguityKind to figure out what kind of ambiguity we hav...
@ 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.
OptionalUnsigned< unsigned > UnsignedOrNone
const FunctionProtoType * T
@ Off
Never emit colors regardless of the output stream.
U cast(CodeGen::Address addr)
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 int32_t
Describes a memory block created by an allocation site.
const bool IsConst
Flag indicating if the block is mutable.
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.
SourceLocation getLocation() const
QualType getDataType(const ASTContext &Ctx) const
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 bool IsTemporary
Flag indicating if the block is a temporary.
const Record *const ElemRecord
Pointer to the record, if block contains records.
const Expr * asExpr() const
Descriptor used for global variables.
Inline descriptor embedded in structures and arrays.
OpaquePointer withFieldType(const Type *FieldTy, std::optional< bool > PastEnd=std::nullopt) const
llvm::PointerIntPair< const Type *, 2, unsigned > FieldType
OpaquePointer withPastEnd(bool PastEnd) const
QualType getSurroundingArray() const
If this is pointing to an array element, return the array.
const PointerPathEntry * Path
bool isArrayElement() const
QualType getFieldType() const
OpaquePointer withPath(const PointerPathEntry *Path, unsigned PathLength, const Type *FieldTy, std::optional< bool > PastEnd=std::nullopt) const
static PointerPathEntry array(int64_t Index)
static PointerPathEntry field(const FieldDecl *FD)
static PointerPathEntry negativeArray(int64_t Index)
static PointerPathEntry base(const CXXRecordDecl *RD, bool Virtual=false)
const Record * getRecord() const
const FieldDecl * getField() const
const Block * block() const
Lifetime getLifetime() const
PtrView stripBaseCasts() const