26#include "llvm/ADT/StringExtras.h"
32 llvm::report_fatal_error(
"Interpreter cannot return values");
45 if (S.Stk.pop<
bool>()) {
52 if (!S.Stk.pop<
bool>()) {
59#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)
60#pragma optimize("", off)
65 [[maybe_unused]]
CodePtr PCBefore = RealPC;
66 size_t StackSizeBefore = S.Stk.size();
68 auto SpeculativeInterp = [&S, RealPC]() ->
bool {
74 if (Op == OP_EndSpeculation)
84 llvm_unreachable(
"We didn't see an EndSpeculation op?");
87 if (SpeculativeInterp()) {
89 const auto &Ptr = S.Stk.pop<
Pointer>();
90 assert(S.Stk.size() == StackSizeBefore);
96 assert(S.Stk.size() == StackSizeBefore);
100 if (!S.inConstantContext())
103 S.Stk.clearTo(StackSizeBefore);
108 assert(*RealPC == *PCBefore);
115 assert(Offset >= ParamSize);
116 RealPC += Offset - ParamSize;
118 [[maybe_unused]]
CodePtr PCCopy = RealPC;
119 assert(PCCopy.
read<
Opcode>() == OP_EndSpeculation);
124#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)
125#pragma optimize("", on)
131 S.FFDiag(
E, diag::note_constexpr_var_init_unknown, 1) << VD;
144 if (isa<ParmVarDecl>(
D)) {
145 if (
D->getType()->isReferenceType()) {
146 if (S.inConstantContext() && S.
getLangOpts().CPlusPlus &&
154 S.FFDiag(
Loc, diag::note_constexpr_function_param_value_unknown) <<
D;
162 if (!
D->getType().isConstQualified()) {
164 }
else if (
const auto *VD = dyn_cast<VarDecl>(
D)) {
165 if (!VD->getAnyInitializer()) {
169 S.FFDiag(
Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
170 S.Note(VD->getLocation(), diag::note_declared_at);
188 if (
const auto *VarD = dyn_cast<VarDecl>(VD);
189 VarD && VarD->getType().isConstQualified() &&
190 !VarD->getAnyInitializer()) {
197 if (isa<ObjCIvarDecl>(VD))
201 S.FFDiag(
Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;
207 S.
getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr
208 : diag::note_constexpr_ltor_non_integral,
220 const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(
228 if (B->
getEvalID() != S.Ctx.getEvalID() &&
231 S.FFDiag(
E, diag::note_constexpr_access_static_temporary, 1) << AK;
233 diag::note_constexpr_temporary_here);
245 if (S.P.getCurrentDecl() == ID)
248 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
266 if (S.Current->Caller &&
Func->isVariadic()) {
271 const Expr *
const *Args =
nullptr;
272 unsigned NumArgs = 0;
273 const Expr *CallSite = S.Current->Caller->getExpr(S.Current->getRetPC());
274 if (
const auto *CE = dyn_cast<CallExpr>(CallSite)) {
275 Args = CE->getArgs();
276 NumArgs = CE->getNumArgs();
277 }
else if (
const auto *CE = dyn_cast<CXXConstructExpr>(CallSite)) {
278 Args = CE->getArgs();
279 NumArgs = CE->getNumArgs();
281 assert(
false &&
"Can't get arguments from that expression type");
283 assert(NumArgs >=
Func->getNumWrittenParams());
284 NumVarArgs = NumArgs - (
Func->getNumWrittenParams() +
285 isa<CXXOperatorCallExpr>(CallSite));
286 for (
unsigned I = 0; I != NumVarArgs; ++I) {
287 const Expr *A = Args[NumArgs - 1 - I];
299 if (!
P.isBlockPointer())
303 return isa_and_nonnull<ParmVarDecl>(
P.getDeclDesc()->asValueDecl());
305 return P.getDeclDesc()->IsConstexprUnknown;
337 while (!
U.isRoot() && !
U.isActive()) {
342 if (
U.getRecord() &&
U.getRecord()->isAnonymousUnion())
362 if (!
U.getFieldDesc()->isUnion())
366 assert(!
C.isActive());
367 const FieldDecl *InactiveField =
C.getField();
368 assert(InactiveField);
371 const Record *R =
U.getRecord();
372 assert(R && R->
isUnion() &&
"Not a union");
375 for (
const Record::Field &F : R->
fields()) {
376 const Pointer &Field =
U.atField(F.Offset);
377 if (Field.isActive()) {
378 ActiveField = Field.getField();
384 S.FFDiag(
Loc, diag::note_constexpr_access_inactive_union_member)
385 << AK << InactiveField << !ActiveField << ActiveField;
397 if (S.checkingPotentialConstantExpression() && S.
getLangOpts().CPlusPlus &&
410 S.FFDiag(
E, diag::note_constexpr_unsized_array_indexed);
417 const auto &Src = S.Current->getSource(OpPC);
420 S.FFDiag(Src, diag::note_constexpr_null_subobject) <<
CSK_Field;
422 S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
428 const auto &Src = S.Current->getSource(OpPC);
431 S.FFDiag(Src, diag::note_constexpr_access_deleted_object) << AK;
432 }
else if (!S.checkingPotentialConstantExpression()) {
434 S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
437 S.Note(Ptr.
getDeclLoc(), diag::note_constexpr_temporary_here);
439 S.Note(Ptr.
getDeclLoc(), diag::note_declared_at);
452 if (!
D ||
D == S.EvaluatingDecl ||
D->isConstexpr())
458 if (
const auto *VD = dyn_cast_if_present<VarDecl>(S.EvaluatingDecl);
474 S.CCEDiag(S.Current->getLocation(OpPC),
476 ? diag::note_constexpr_ltor_non_constexpr
477 : diag::note_constexpr_ltor_non_integral,
482 S.CCEDiag(S.Current->getLocation(OpPC));
513 S.FFDiag(
Loc, diag::note_constexpr_null_subobject)
514 << CSK << S.Current->getRange(OpPC);
525 S.FFDiag(
Loc, diag::note_constexpr_access_past_end)
526 << AK << S.Current->getRange(OpPC);
536 S.FFDiag(
Loc, diag::note_constexpr_past_end_subobject)
537 << CSK << S.Current->getRange(OpPC);
547 S.FFDiag(
Loc, diag::note_constexpr_past_end_subobject)
548 << CSK << S.Current->getRange(OpPC);
559 if (Offset < PtrOffset && (PtrOffset - Offset) >= MinOffset)
562 const auto *
E = cast<CastExpr>(S.Current->getExpr(OpPC));
566 S.CCEDiag(
E, diag::note_constexpr_invalid_downcast)
567 << MostDerivedQT << TargetQT;
573 assert(Ptr.
isLive() &&
"Pointer is not live");
585 if (llvm::is_contained(S.InitializingBlocks, Ptr.
block()))
590 S.FFDiag(
Loc, diag::note_constexpr_modify_const_type) << Ty;
595 assert(Ptr.
isLive() &&
"Pointer is not live");
614 S.FFDiag(
Loc, diag::note_constexpr_access_mutable, 1) <<
AK_Read << Field;
615 S.Note(Field->getLocation(), diag::note_declared_at);
632 while (!
P.isRoot()) {
633 if (
P.getType().isVolatileQualified())
641 if (
const auto *F =
P.getField()) {
643 Loc = F->getLocation();
645 }
else if (
auto *VD =
P.getFieldDesc()->asValueDecl()) {
647 Loc = VD->getLocation();
651 if (
const auto *
E =
P.getFieldDesc()->asExpr())
655 S.FFDiag(S.Current->getLocation(OpPC),
656 diag::note_constexpr_access_volatile_obj, 1)
657 << AK << DiagKind << ND;
658 S.Note(
Loc, diag::note_constexpr_volatile_here) << DiagKind;
671 if (Extern && S.checkingPotentialConstantExpression())
675 VD && (VD->isConstexpr() || VD->hasGlobalStorage())) {
677 if (VD == S.EvaluatingDecl &&
678 !(S.
getLangOpts().CPlusPlus23 && VD->getType()->isReferenceType())) {
686 S.FFDiag(
Loc, diag::note_constexpr_access_uninit)
692 if (VD->getAnyInitializer()) {
694 S.FFDiag(
Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
695 S.Note(VD->getLocation(), diag::note_declared_at);
702 if (!S.checkingPotentialConstantExpression()) {
703 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
704 << AK <<
true << S.Current->getRange(OpPC);
714 if (!S.checkingPotentialConstantExpression()) {
715 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
716 << AK <<
false << S.Current->getRange(OpPC);
727 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_var_init_weak)
729 S.Note(VD->getLocation(), diag::note_declared_at);
761 S.FFDiag(S.Current->getLocation(OpPC),
762 diag::note_constexpr_access_volatile_obj, 1)
764 S.Note(
D->
getLocation(), diag::note_constexpr_volatile_here) << 1;
776 if (!Desc.IsInitialized)
784 S.FFDiag(S.Current->getLocation(OpPC),
785 diag::note_constexpr_access_volatile_obj, 1)
787 S.Note(
D->
getLocation(), diag::note_constexpr_volatile_here) << 1;
797 const auto &Src = S.Current->getSource(OpPC);
800 S.FFDiag(Src, diag::note_constexpr_null_subobject) <<
CSK_Field;
802 S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
922 S.CCEDiag(
Loc, diag::note_constexpr_virtual_call);
926 if (S.checkingPotentialConstantExpression() && S.Current->getDepth() != 0)
943 if (S.Current->getLocation(OpPC).isMacroID() &&
949 Name ==
"__assert_rtn" || Name ==
"__assert_fail" || Name ==
"_wassert";
951 S.FFDiag(S.Current->getLocation(OpPC),
952 diag::note_constexpr_assert_failed);
966 const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
967 if (CD && CD->isInheritingConstructor()) {
968 const auto *Inherited = CD->getInheritedConstructor().getConstructor();
969 if (!Inherited->isConstexpr())
970 DiagDecl = CD = Inherited;
975 if (CD && CD->getParent()->isInvalidDecl())
981 if (CD && CD->isInheritingConstructor()) {
982 S.FFDiag(S.Current->getLocation(OpPC),
983 diag::note_constexpr_invalid_inhctor, 1)
984 << CD->getInheritedConstructor().getConstructor()->getParent();
985 S.Note(DiagDecl->
getLocation(), diag::note_declared_at);
992 if (!IsDefined && !IsExtern && DiagDecl->
isConstexpr() &&
993 S.checkingPotentialConstantExpression())
1002 S.FFDiag(S.Current->getLocation(OpPC),
1003 diag::note_constexpr_invalid_function, 1)
1008 diag::note_declared_at);
1010 S.Note(DiagDecl->
getLocation(), diag::note_declared_at);
1013 S.FFDiag(S.Current->getLocation(OpPC),
1014 diag::note_invalid_subexpr_in_const_expr);
1021 if ((S.Current->getDepth() + 1) > S.
getLangOpts().ConstexprCallDepth) {
1022 S.FFDiag(S.Current->getSource(OpPC),
1023 diag::note_constexpr_depth_limit_exceeded)
1035 const Expr *
E = S.Current->getExpr(OpPC);
1037 bool IsImplicit =
false;
1038 if (
const auto *TE = dyn_cast<CXXThisExpr>(
E))
1039 IsImplicit = TE->isImplicit();
1040 S.FFDiag(
E, diag::note_constexpr_this) << IsImplicit;
1049 APFloat::opStatus Status,
FPOptions FPO) {
1056 S.CCEDiag(
E, diag::note_constexpr_float_arithmetic)
1057 <<
true << S.Current->getRange(OpPC);
1058 return S.noteUndefinedBehavior();
1063 if (S.inConstantContext())
1066 if ((Status & APFloat::opInexact) &&
1071 S.FFDiag(
E, diag::note_constexpr_dynamic_rounding);
1075 if ((Status != APFloat::opOK) &&
1078 FPO.getAllowFEnvAccess())) {
1080 S.FFDiag(
E, diag::note_constexpr_float_arithmetic_strict);
1084 if ((Status & APFloat::opStatus::opInvalidOp) &&
1100 S.CCEDiag(
E, diag::note_constexpr_new);
1107 const Expr *NewExpr) {
1108 if (AllocForm == DeleteForm)
1114 S.FFDiag(
E, diag::note_constexpr_new_delete_mismatch)
1115 <<
static_cast<int>(DeleteForm) <<
static_cast<int>(AllocForm)
1117 S.Note(NewExpr->
getExprLoc(), diag::note_constexpr_dynamic_alloc_here)
1125 if (isa_and_nonnull<CXXNewExpr>(Source))
1128 if (
const auto *CE = dyn_cast_if_present<CallExpr>(Source);
1129 CE && CE->getBuiltinCallee() == Builtin::BI__builtin_operator_new)
1132 if (
const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(Source);
1133 MCE && MCE->getMethodDecl()->
getIdentifier()->isStr(
"allocate"))
1138 S.FFDiag(
Loc, diag::note_constexpr_delete_not_heap_alloc)
1142 S.Note(Ptr.
getDeclLoc(), diag::note_constexpr_temporary_here);
1144 S.Note(Ptr.
getDeclLoc(), diag::note_declared_at);
1168 S.FFDiag(
E, diag::note_constexpr_modify_global);
1174 const CallExpr *CE,
unsigned ArgSize) {
1177 unsigned Offset = 0;
1179 for (
const Expr *Arg : Args) {
1180 if (NonNullArgs[Index] && Arg->getType()->isPointerType()) {
1184 S.CCEDiag(
Loc, diag::note_non_null_attribute_failed);
1203 S.Current->getFunction()->isDestructor()) {
1205 S.FFDiag(
Loc, diag::note_constexpr_double_destroy);
1213 const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor);
1218 return Call(S, OpPC, DtorFunc, 0);
1241 for (
int I =
static_cast<int>(N) - 1; I >= 0; --I) {
1255 return DD->isVirtual();
1260 bool IsGlobalDelete) {
1266 const Expr *Source =
nullptr;
1267 const Block *BlockToDelete =
nullptr;
1283 BlockToDelete = Ptr.
block();
1287 if (std::optional<DynamicAllocator::Form> AllocForm =
1288 Allocator.getAllocationForm(Source)) {
1299 if (!DeleteIsArrayForm && Ptr.
getType() != InitialType &&
1301 S.FFDiag(S.Current->getSource(OpPC),
1302 diag::note_constexpr_delete_base_nonvirt_dtor)
1303 << InitialType << Ptr.
getType();
1310 S.FFDiag(
Loc, diag::note_constexpr_delete_subobject)
1320 if (!DeleteIsArrayForm && !IsGlobalDelete) {
1325 return DD->isVirtual() ? DD->getOperatorDelete() :
nullptr;
1334 S.FFDiag(S.Current->getSource(OpPC),
1335 diag::note_constexpr_new_non_replaceable)
1336 << isa<CXXMethodDecl>(VirtualDelete) << VirtualDelete;
1342 assert(BlockToDelete);
1348 if (!Allocator.deallocate(Source, BlockToDelete, S)) {
1351 S.FFDiag(
Loc, diag::note_constexpr_double_delete);
1360 if (S.EvaluatingDecl && !S.EvaluatingDecl->isConstexpr())
1371 S.CCEDiag(
Loc, diag::note_constexpr_unscoped_enum_out_of_range)
1372 << llvm::toString(
Value, 10) <<
Min.getSExtValue() <<
Max.getSExtValue()
1376 S.CCEDiag(
Loc, diag::note_constexpr_unscoped_enum_out_of_range)
1377 << llvm::toString(
Value, 10) <<
Min.getZExtValue() <<
Max.getZExtValue()
1400 if (S.Current->getFunction() && S.Current->getFunction()->isConstructor() &&
1401 S.Current->getThis().getDeclDesc()->asDecl() == S.EvaluatingDecl) {
1405 const Expr *
E = S.Current->getExpr(OpPC);
1407 S.FFDiag(
E, diag::note_constexpr_nonliteral) <<
E->
getType();
1409 S.FFDiag(
E, diag::note_invalid_subexpr_in_const_expr);
1415 if (S.
getLangOpts().CPlusPlus && S.inConstantContext() &&
1435 S.FFDiag(S.Current->getSource(OpPC),
1436 diag::note_constexpr_access_unreadable_object)
1449 const auto &Ptr = S.Stk.peek<
Pointer>();
1450 return getField(S, OpPC, Ptr, Off);
1454 const auto &Ptr = S.Stk.pop<
Pointer>();
1455 return getField(S, OpPC, Ptr, Off);
1460 assert(
Func->isConstructor());
1462 if (
Func->getParentDecl()->isInvalidDecl())
1471 if (
D->ElemRecord->getNumVirtualBases() == 0)
1474 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_virtual_base)
1475 <<
Func->getParentDecl();
1490 S.FFDiag(
E, diag::note_constexpr_modify_global);
1498 .compileFunc(
Func->getDecl()->getMostRecentDecl(),
1503 uint32_t VarArgSize) {
1504 if (
Func->hasThisPointer()) {
1505 size_t ArgSize =
Func->getArgSize() + VarArgSize;
1513 if (!(S.Current->getFunction() &&
1514 S.Current->getFunction()->isLambdaStaticInvoker() &&
1515 Func->isLambdaCallOperator())) {
1520 if (S.checkingPotentialConstantExpression())
1524 if (!
Func->isFullyCompiled())
1533 auto NewFrame = std::make_unique<InterpFrame>(S,
Func, OpPC, VarArgSize);
1535 S.Current = NewFrame.get();
1542 assert(S.Current == FrameBefore);
1548 S.Current = FrameBefore;
1552 uint32_t VarArgSize) {
1554 auto cleanup = [&]() ->
bool {
1559 if (
Func->hasThisPointer()) {
1560 size_t ArgSize =
Func->getArgSize() + VarArgSize;
1568 if (ThisPtr.isDummy() &&
Func->isVirtual())
1575 if (S.Current->getFunction() &&
1576 S.Current->getFunction()->isLambdaStaticInvoker() &&
1577 Func->isLambdaCallOperator()) {
1578 assert(ThisPtr.isZero());
1582 if (!
Func->isConstructor() && !
Func->isDestructor() &&
1592 if (
Func->isConstructor() ||
Func->isDestructor())
1593 S.InitializingBlocks.push_back(ThisPtr.block());
1596 if (!
Func->isFullyCompiled())
1605 if (
Func->hasThisPointer() && S.checkingPotentialConstantExpression() &&
1606 !
Func->isConstructor())
1612 auto NewFrame = std::make_unique<InterpFrame>(S,
Func, OpPC, VarArgSize);
1614 S.Current = NewFrame.get();
1622 if (
Func->isConstructor() ||
Func->isDestructor())
1623 S.InitializingBlocks.pop_back();
1628 S.Current = FrameBefore;
1633 assert(S.Current == FrameBefore);
1638 uint32_t VarArgSize) {
1639 assert(
Func->hasThisPointer());
1640 assert(
Func->isVirtual());
1641 size_t ArgSize =
Func->getArgSize() + VarArgSize;
1646 if (!
Func->isFullyCompiled())
1652 if (Callee->isPureVirtual()) {
1653 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_pure_virtual_call,
1656 S.Note(Callee->getLocation(), diag::note_declared_at);
1668 DynamicDecl =
DynamicType->getPointeeCXXRecordDecl();
1672 assert(DynamicDecl);
1674 const auto *StaticDecl = cast<CXXRecordDecl>(
Func->getParentDecl());
1675 const auto *InitialFunction = cast<CXXMethodDecl>(Callee);
1678 if (StaticDecl != DynamicDecl) {
1681 Overrider = S.getContext().getOverridingFunction(DynamicDecl, StaticDecl,
1685 Overrider = InitialFunction;
1688 if (Overrider != InitialFunction) {
1693 const Expr *
E = S.Current->getExpr(OpPC);
1697 Func = S.getContext().getOrCreateFunction(Overrider);
1700 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
1701 if (
Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
1705 while (ThisPtr.isBaseClass())
1706 ThisPtr = ThisPtr.getBase();
1710 if (!
Call(S, OpPC,
Func, VarArgSize))
1715 if (Overrider != InitialFunction &&
1717 InitialFunction->getReturnType()->isPointerOrReferenceType()) {
1726 unsigned Offset = S.getContext().collectBaseOffset(
1736 uint32_t BuiltinID) {
1739 if (BuiltinID == Builtin::BI__builtin_operator_new &&
1740 S.checkingPotentialConstantExpression())
1751 const auto *
E = cast<CallExpr>(S.Current->getExpr(OpPC));
1752 S.FFDiag(
E, diag::note_constexpr_null_callee)
1788 return CallVirt(S, OpPC, F, VarArgSize);
1790 return Call(S, OpPC, F, VarArgSize);
1796 for (
const Record::Field &Fi : R->fields())
1804 for (
unsigned I = 0; I != FieldDesc->getNumElems(); ++I)
1813 const auto &Ptr = S.Stk.peek<
Pointer>();
1825 for (
const Record::Field &Fi : R->fields())
1834 for (
unsigned I = 0; I != FieldDesc->getNumElems(); ++I)
1844 const auto &Ptr = S.Stk.peek<
Pointer>();
1849 if (Ptr.isArrayElement())
1858 const auto &Ptr = S.Stk.pop<
Pointer>();
1863 if (Ptr.isArrayElement())
1871 std::optional<uint64_t> ArraySize) {
1915 const auto *NewExpr = cast<CXXNewExpr>(
E);
1921 NewExpr->getAllocatedType(),
1922 APInt(64,
static_cast<uint64_t
>(*ArraySize),
false),
nullptr,
1925 AllocType = NewExpr->getAllocatedType();
1928 unsigned StorageSize = 1;
1929 unsigned AllocSize = 1;
1930 if (
const auto *CAT = dyn_cast<ConstantArrayType>(AllocType))
1931 AllocSize = CAT->getZExtSize();
1932 if (
const auto *CAT = dyn_cast<ConstantArrayType>(StorageType))
1933 StorageSize = CAT->getZExtSize();
1935 if (AllocSize > StorageSize ||
1938 S.FFDiag(S.Current->getLocation(OpPC),
1939 diag::note_constexpr_placement_new_wrong_type)
1940 << StorageType << AllocType;
1954 if (
const auto *NewExpr = dyn_cast<CXXNewExpr>(
E)) {
1955 const FunctionDecl *OperatorNew = NewExpr->getOperatorNew();
1957 if (NewExpr->getNumPlacementArgs() > 0) {
1959 if (S.
getLangOpts().CPlusPlus26 || S.Current->isStdFunction())
1961 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement)
1965 ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
1966 S.FFDiag(S.Current->getSource(OpPC),
1967 diag::note_constexpr_new_non_replaceable)
1968 << isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
1971 NewExpr->getNumPlacementArgs() == 1 &&
1972 !OperatorNew->isReservedGlobalPlacementOperator()) {
1974 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement)
1981 const auto *DeleteExpr = cast<CXXDeleteExpr>(
E);
1982 const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelete();
1984 ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
1985 S.FFDiag(S.Current->getSource(OpPC),
1986 diag::note_constexpr_new_non_replaceable)
1987 << isa<CXXMethodDecl>(OperatorDelete) << OperatorDelete;
1997 const Expr *
E = S.Current->getExpr(OpPC);
1998 if (S.checkingForUndefinedBehavior()) {
2000 E->
getExprLoc(), diag::warn_fixedpoint_constant_overflow)
2003 S.CCEDiag(
E, diag::note_constexpr_overflow)
2005 return S.noteUndefinedBehavior();
2011 diag::err_shufflevector_minus_one_is_undefined_behavior_constexpr)
2017 const Pointer &Ptr,
unsigned BitWidth) {
2024 S.CCEDiag(
E, diag::note_constexpr_invalid_cast)
2025 << 2 << S.
getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2063 bool TargetIsUCharOrByte) {
2065 if (!HasIndeterminateBits)
2069 if (TargetIsUCharOrByte)
2072 const Expr *
E = S.Current->getExpr(OpPC);
2074 S.FFDiag(
E, diag::note_constexpr_bit_cast_indet_dest)
2080 const Type *TypeInfoType) {
2081 S.Stk.push<
Pointer>(TypePtr, TypeInfoType);
2086 const auto &
P = S.Stk.pop<
Pointer>();
2088 if (!
P.isBlockPointer())
2092 CanQualType T =
P.getDeclPtr().getType()->getCanonicalTypeUnqualified();
2095 if (S.Current->getFunction()) {
2098 Func && (
Func->isConstructor() ||
Func->isDestructor()) &&
2099 P.block() ==
Frame->getThis().block()) {
2101 Func->getParentDecl());
2107 S.Stk.push<
Pointer>(
T->getTypePtr(), TypeInfoType);
2112 const auto *
E = cast<CXXTypeidExpr>(S.Current->getExpr(OpPC));
2113 S.CCEDiag(
E, diag::note_constexpr_typeid_polymorphic)
2128 int32_t IndexDiff = RHSOffset - LHSOffset;
2129 if (IndexDiff < 0) {
2130 if (
static_cast<int32_t
>(LHSLength) < -IndexDiff)
2132 LHSStr = LHSStr.drop_front(-IndexDiff);
2134 if (
static_cast<int32_t
>(RHSLength) < IndexDiff)
2136 RHSStr = RHSStr.drop_front(IndexDiff);
2139 unsigned ShorterCharWidth;
2142 if (LHSLength < RHSLength) {
2155 for (
unsigned NullByte : llvm::seq(ShorterCharWidth)) {
2156 if (Shorter.size() + NullByte >= Longer.size())
2158 if (Longer[Shorter.size() + NullByte])
2161 return Shorter == Longer.take_front(Shorter.size());
2169 if (!Val.singleWord()) {
2170 uint64_t *NewMemory =
new (S.P) uint64_t[Val.numWords()];
2171 Val.take(NewMemory);
2175 if (!Val.singleWord()) {
2176 uint64_t *NewMemory =
new (S.P) uint64_t[Val.numWords()];
2177 Val.take(NewMemory);
2181 if (!Val.singleWord()) {
2182 uint64_t *NewMemory =
new (S.P) uint64_t[Val.numWords()];
2183 Val.take(NewMemory);
2188template <
typename T>
2190 assert(needsAlloc<T>());
2191 auto &Val = Ptr.
deref<
T>();
2192 if (!Val.singleWord()) {
2193 uint64_t *NewMemory =
new (S.P) uint64_t[Val.numWords()];
2194 Val.take(NewMemory);
2200 for (
const Record::Field &Fi : R->fields()) {
2201 if (Fi.Desc->isPrimitive()) {
2203 copyPrimitiveMemory<T>(S, Ptr.atField(Fi.Offset));
2213 unsigned NumElems =
D->getNumElems();
2217 if (
D->isPrimitiveArray()) {
2221 assert(NumElems >= 1);
2223 bool AllSingleWord =
true;
2225 if (!EP.
deref<
T>().singleWord()) {
2226 copyPrimitiveMemory<T>(S, EP);
2227 AllSingleWord = false;
2232 for (
unsigned I = 1; I !=
D->getNumElems(); ++I) {
2237 assert(
D->isCompositeArray());
2238 for (
unsigned I = 0; I !=
D->getNumElems(); ++I) {
2259#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)
2260#pragma optimize("", off)
2268 assert(!S.Current->isRoot());
2269 CodePtr PC = S.Current->getPC();
2281#include "Opcodes.inc"
2287#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)
2288#pragma optimize("", on)
Defines the clang::ASTContext interface.
ASTImporterLookupTable & LT
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 BCP(InterpState &S, CodePtr &RealPC, int32_t Offset, PrimType PT)
static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset)
static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, const ValueDecl *VD)
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 bool RetValue(InterpState &S, CodePtr &Pt)
static StringRef getIdentifier(const Token &Tok)
#define TYPE_SWITCH_ALLOC(Expr, B)
#define TYPE_SWITCH(Expr, B)
a trap message and trap category.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
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.
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.
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.
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 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 isConstant(const ASTContext &Ctx) const
ASTContext & getASTContext() const
const LangOptions & getLangOpts() const
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...
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.
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
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
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.
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.
Manages dynamic memory allocations done during bytecode interpretation.
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.
const Function * getFunction() const
bool isVirtual() const
Checks if the function is virtual.
bool isDefined() const
Checks if the function is defined.
bool hasNonNullAttr() const
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 Integral from(ValT Value)
Frame storing local variables.
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.
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.
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.
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 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.
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.
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.
bool isOnePastEnd() const
Checks if the index is one past end.
uint64_t getIntegerRepresentation() const
const FieldDecl * getField() const
Returns the field information.
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
void startLifetime() const
bool isBlockPointer() const
bool isTemporary() const
Checks if the storage is temporary.
const FunctionPointer & asFunctionPointer() const
SourceLocation getDeclLoc() const
const Block * block() const
bool isFunctionPointer() const
Pointer getDeclPtr() const
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
bool isBaseClass() const
Checks if a structure is a base class.
size_t elemSize() const
Returns the element size of 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.
const std::byte * getRawAddress() const
If backed by actual data (i.e.
bool isField() const
Checks if the item is a field in an object.
const Record * getRecord() const
Returns the record descriptor of a class.
Structure/Class descriptor.
bool isUnion() const
Checks if the record is a union.
const CXXDestructorDecl * getDestructor() const
Returns the destructor of the record, if any.
llvm::iterator_range< const_field_iter > fields() const
Describes the statement/declaration an opcode was generated from.
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)
static void startLifetimeRecurse(const Pointer &Ptr)
bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
static bool CheckLifetime(InterpState &S, CodePtr OpPC, Lifetime LT, AccessKinds AK)
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 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 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.
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks the 'this' pointer.
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
static bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *CE, unsigned ArgSize)
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)
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.
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 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 CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits, bool TargetIsUCharOrByte)
static void popArg(InterpState &S, const Expr *Arg)
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 StartLifetime(InterpState &S, CodePtr OpPC)
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be stored in a block.
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.
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 CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T)
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
static void compileFunction(InterpState &S, const Function *Func)
bool FinishInitGlobal(InterpState &S, CodePtr OpPC)
bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC, const Function *Func)
static void copyPrimitiveMemory(InterpState &S, const Pointer &Ptr, PrimType T)
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)
static bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the variable has externally defined storage.
bool isConstexprUnknown(const Pointer &P)
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)
bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, const CallExpr *CE)
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
static void endLifetimeRecurse(const Pointer &Ptr)
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 CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
The JSON file list parser is used to communicate input to InstallAPI.
@ 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.
const FunctionProtoType * T
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 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
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
const VarDecl * asVarDecl() 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
Descriptor used for global variables.
Inline descriptor embedded in structures and arrays.
IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const