24#include "llvm/ADT/APSInt.h"
25#include "llvm/ADT/StringExtras.h"
33 llvm::report_fatal_error(
"Interpreter cannot return values");
46 if (S.Stk.pop<
bool>()) {
53 if (!S.Stk.pop<
bool>()) {
62 S.FFDiag(
E, diag::note_constexpr_var_init_unknown, 1) << VD;
72 if (isa<ParmVarDecl>(
D)) {
74 S.FFDiag(
E, diag::note_constexpr_function_param_value_unknown) <<
D;
82 if (!
D->getType().isConstQualified())
84 else if (
const auto *VD = dyn_cast<VarDecl>(
D);
85 VD && !VD->getAnyInitializer())
97 if (
const auto *VarD = dyn_cast<VarDecl>(VD);
98 VarD && VarD->getType().isConstQualified() &&
99 !VarD->getAnyInitializer()) {
106 if (isa<ObjCIvarDecl>(VD))
110 S.FFDiag(
Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;
116 S.
getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr
117 : diag::note_constexpr_ltor_non_integral,
133 while (!
U.isRoot() &&
U.inUnion() && !
U.isActive()) {
141 const FieldDecl *InactiveField =
C.getField();
142 assert(InactiveField);
156 if (!
U.getFieldDesc()->isUnion())
160 const Record *R =
U.getRecord();
161 assert(R && R->
isUnion() &&
"Not a union");
164 for (
const Record::Field &F : R->
fields()) {
165 const Pointer &Field =
U.atField(F.Offset);
166 if (Field.isActive()) {
167 ActiveField = Field.getField();
173 S.FFDiag(
Loc, diag::note_constexpr_access_inactive_union_member)
174 << AK << InactiveField << !ActiveField << ActiveField;
187 if (S.P.getCurrentDecl() == ID)
191 S.FFDiag(
E, diag::note_constexpr_access_static_temporary, 1) << AK;
192 S.Note(Ptr.
getDeclLoc(), diag::note_constexpr_temporary_here);
203 if (S.P.getCurrentDecl() == ID)
206 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
221 const Function *CurFunc = S.Current->getFunction();
231 cast<CallExpr>(S.Current->Caller->getExpr(S.Current->getRetPC()));
232 for (int32_t I = CE->getNumArgs() - 1; I >= 0; --I) {
233 const Expr *A = CE->getArg(I);
239 if (S.Current->Caller && CurFunc->
isVariadic()) {
244 const Expr *
const *Args =
nullptr;
245 unsigned NumArgs = 0;
246 const Expr *CallSite = S.Current->Caller->getExpr(S.Current->getRetPC());
247 if (
const auto *CE = dyn_cast<CallExpr>(CallSite)) {
248 Args = CE->getArgs();
249 NumArgs = CE->getNumArgs();
250 }
else if (
const auto *CE = dyn_cast<CXXConstructExpr>(CallSite)) {
251 Args = CE->getArgs();
252 NumArgs = CE->getNumArgs();
254 assert(
false &&
"Can't get arguments from that expression type");
258 isa<CXXOperatorCallExpr>(CallSite));
259 for (
unsigned I = 0; I != NumVarArgs; ++I) {
260 const Expr *A = Args[NumArgs - 1 - I];
267 S.Current->popArgs();
278 if (!S.checkingPotentialConstantExpression() && S.
getLangOpts().CPlusPlus) {
289 S.FFDiag(
E, diag::note_constexpr_unsized_array_indexed);
296 const auto &Src = S.Current->getSource(OpPC);
299 S.FFDiag(Src, diag::note_constexpr_null_subobject) <<
CSK_Field;
301 S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
307 const auto &Src = S.Current->getSource(OpPC);
310 S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
313 S.Note(Ptr.
getDeclLoc(), diag::note_constexpr_temporary_here);
315 S.Note(Ptr.
getDeclLoc(), diag::note_declared_at);
326 auto IsConstType = [&S](
const VarDecl *VD) ->
bool {
329 if (
T.isConstant(S.getCtx()))
335 T.isConstQualified();
337 if (
T.isConstQualified())
344 return PT->getPointeeType().isConstQualified();
350 D &&
D->hasGlobalStorage() &&
D != S.EvaluatingDecl && !IsConstType(
D)) {
369 S.FFDiag(
Loc, diag::note_constexpr_null_subobject)
370 << CSK << S.Current->getRange(OpPC);
380 S.FFDiag(
Loc, diag::note_constexpr_access_past_end)
381 << AK << S.Current->getRange(OpPC);
390 S.FFDiag(
Loc, diag::note_constexpr_past_end_subobject)
391 << CSK << S.Current->getRange(OpPC);
401 S.FFDiag(
Loc, diag::note_constexpr_past_end_subobject)
402 << CSK << S.Current->getRange(OpPC);
413 if (Offset < PtrOffset && (PtrOffset - Offset) >= MinOffset)
416 const auto *
E = cast<CastExpr>(S.Current->getExpr(OpPC));
420 S.CCEDiag(
E, diag::note_constexpr_invalid_downcast)
421 << MostDerivedQT << TargetQT;
427 assert(Ptr.
isLive() &&
"Pointer is not live");
435 if (S.Current->getFunction()) {
438 Func && (
Func->isConstructor() ||
Func->isDestructor()) &&
450 S.FFDiag(
Loc, diag::note_constexpr_modify_const_type) << Ty;
455 assert(Ptr.
isLive() &&
"Pointer is not live");
467 S.FFDiag(
Loc, diag::note_constexpr_access_mutable, 1) <<
AK_Read << Field;
468 S.Note(Field->getLocation(), diag::note_declared_at);
487 S.FFDiag(
Loc, diag::note_constexpr_access_volatile_type) << AK << PtrType;
503 if (VD->getAnyInitializer()) {
504 S.FFDiag(
Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
505 S.Note(VD->getLocation(), diag::note_declared_at);
512 if (!S.checkingPotentialConstantExpression()) {
513 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
514 << AK <<
true << S.Current->getRange(OpPC);
525 if ((!VD->hasConstantInitialization() &&
526 VD->mightBeUsableInConstantExpressions(S.getCtx())) ||
528 !VD->hasICEInitializer(S.getCtx()))) {
530 S.FFDiag(
Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
531 S.Note(VD->getLocation(), diag::note_declared_at);
627 S.CCEDiag(
Loc, diag::note_constexpr_virtual_call);
649 const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
650 if (CD && CD->isInheritingConstructor()) {
651 const auto *Inherited = CD->getInheritedConstructor().getConstructor();
652 if (!Inherited->isConstexpr())
653 DiagDecl = CD = Inherited;
659 if (CD && CD->isInheritingConstructor()) {
660 S.FFDiag(
Loc, diag::note_constexpr_invalid_inhctor, 1)
661 << CD->getInheritedConstructor().getConstructor()->getParent();
662 S.Note(DiagDecl->
getLocation(), diag::note_declared_at);
669 S.checkingPotentialConstantExpression())
678 S.FFDiag(
Loc, diag::note_constexpr_invalid_function, 1)
683 diag::note_declared_at);
685 S.Note(DiagDecl->
getLocation(), diag::note_declared_at);
688 S.FFDiag(
Loc, diag::note_invalid_subexpr_in_const_expr);
695 if ((S.Current->getDepth() + 1) > S.
getLangOpts().ConstexprCallDepth) {
696 S.FFDiag(S.Current->getSource(OpPC),
697 diag::note_constexpr_depth_limit_exceeded)
711 bool IsImplicit =
false;
712 if (
const auto *
E = dyn_cast_if_present<CXXThisExpr>(
Loc.asExpr()))
713 IsImplicit =
E->isImplicit();
716 S.FFDiag(
Loc, diag::note_constexpr_this) << IsImplicit;
727 S.FFDiag(
E, diag::note_constexpr_pure_virtual_call, 1) << MD;
733 APFloat::opStatus Status) {
741 S.CCEDiag(
E, diag::note_constexpr_float_arithmetic)
742 <<
true << S.Current->getRange(OpPC);
743 return S.noteUndefinedBehavior();
748 if (S.inConstantContext())
753 if ((Status & APFloat::opInexact) &&
757 S.FFDiag(
E, diag::note_constexpr_dynamic_rounding);
761 if ((Status != APFloat::opOK) &&
764 FPO.getAllowFEnvAccess())) {
765 S.FFDiag(
E, diag::note_constexpr_float_arithmetic_strict);
769 if ((Status & APFloat::opStatus::opInvalidOp) &&
784 S.CCEDiag(
E, diag::note_constexpr_new);
790 const Expr *NewExpr) {
791 if (NewWasArray == DeleteIsArray)
799 QualType ElemQT =
D->getType()->getPointeeType();
800 TypeToDiagnose = S.getCtx().getConstantArrayType(
801 ElemQT,
APInt(64,
static_cast<uint64_t
>(
D->getNumElems()),
false),
804 TypeToDiagnose =
D->getType()->getPointeeType();
807 S.FFDiag(
E, diag::note_constexpr_new_delete_mismatch)
808 << DeleteIsArray << 0 << TypeToDiagnose;
809 S.Note(NewExpr->
getExprLoc(), diag::note_constexpr_dynamic_alloc_here)
816 if (Source && isa<CXXNewExpr>(Source))
821 S.FFDiag(
Loc, diag::note_constexpr_delete_not_heap_alloc)
825 S.Note(Ptr.
getDeclLoc(), diag::note_constexpr_temporary_here);
827 S.Note(Ptr.
getDeclLoc(), diag::note_declared_at);
854 S.FFDiag(
E, diag::note_constexpr_modify_global);
860 const CallExpr *CE,
unsigned ArgSize) {
865 for (
const Expr *Arg : Args) {
866 if (NonNullArgs[Index] && Arg->getType()->isPointerType()) {
870 S.CCEDiag(
Loc, diag::note_non_null_attribute_failed);
895 S.FFDiag(
Loc, diag::note_constexpr_double_destroy);
902 const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor);
907 if (!
Call(S, OpPC, DtorFunc, 0))
927 for (
unsigned I = 0; I != Desc->
getNumElems(); ++I) {
943 if (S.EvaluatingDecl && !S.EvaluatingDecl->isConstexpr())
952 S.CCEDiag(
Loc, diag::note_constexpr_unscoped_enum_out_of_range)
953 << llvm::toString(
Value, 10) <<
Min.getSExtValue() <<
Max.getSExtValue()
957 S.CCEDiag(
Loc, diag::note_constexpr_unscoped_enum_out_of_range)
958 << llvm::toString(
Value, 10) <<
Min.getZExtValue() <<
Max.getZExtValue()
969 assert(!S.Current->isRoot());
970 CodePtr PC = S.Current->getPC();
982#include "Opcodes.inc"
Defines the clang::ASTContext interface.
Defines the clang::Expr interface and subclasses for C++ expressions.
static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset)
static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset)
static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, const ValueDecl *VD)
static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result)
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)
#define TYPE_SWITCH(Expr, B)
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Represents a C++ destructor within a class.
Represents a static or instance method of a struct/union/class.
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.
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.
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.
FPOptions getFPFeaturesInEffect(const LangOptions &LO) const
Returns the set of floating point options that apply to this 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.
bool isTrivial() const
Whether this function is "trivial" in some specialized C++ senses.
StorageClass getStorageClass() const
Returns the storage class as written in the source.
bool isConstexpr() const
Whether this is a (C++11) constexpr function or constexpr constructor.
bool isPureVirtual() const
Whether this virtual function is pure, i.e.
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.
PointerType - C99 6.7.5.1 - Pointer Declarators.
A (possibly-)qualified type.
bool isVolatileQualified() const
Determine whether this type is volatile-qualified.
bool isConstQualified() const
Determine whether this type is const-qualified.
Base for LValueReferenceType and RValueReferenceType.
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...
bool isSignedIntegerOrEnumerationType() const
Determines whether this is an integer type that is signed or an enumeration types whose underlying ty...
bool isUnsignedIntegerOrEnumerationType() const
Determines whether this is an integer type that is unsigned or an enumeration types whose underlying ...
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 T * getAs() const
Member-template getAs<specific type>'.
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 hasGlobalStorage() const
Returns true for all variables that do not have local storage.
A memory block, either on the stack or in the heap.
const Descriptor * getDescriptor() const
Returns the block's descriptor.
unsigned getEvalID() const
The Evaluation ID this block was created in.
Pointer into the code segment.
std::enable_if_t<!std::is_pointer< T >::value, T > read()
Reads data and advances the pointer.
Base class for stack frames, shared between VM and walker.
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
bool hasBody() const
Checks if the function already has a body attached.
bool isVirtual() const
Checks if the function is virtual.
bool isUnevaluatedBuiltin() const
bool isConstexpr() const
Checks if the function is valid to call in constexpr.
unsigned getNumWrittenParams() const
Returns the number of parameter this function takes when it's called, i.e excluding the instance poin...
bool isLambdaStaticInvoker() const
Returns whether this function is a lambda static invoker, which we generate custom byte code for.
Frame storing local variables.
A pointer to a memory block, live or dead.
Pointer narrow() const
Restricts the scope of an array element pointer.
bool isInitialized() const
Checks if an object was initialized.
bool isStatic() const
Checks if the storage is static.
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.
bool isActive() const
Checks if the object is active.
bool isConst() const
Checks if an object or a subfield is mutable.
bool isMutable() const
Checks if the field is mutable.
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
QualType getType() const
Returns the type of the innermost field.
bool isLive() const
Checks if the pointer is live.
bool isStaticTemporary() const
Checks if the storage is a static temporary.
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
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 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.
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
bool isBlockPointer() const
bool isTemporary() const
Checks if the storage is temporary.
SourceLocation getDeclLoc() const
const Block * block() const
Pointer getDeclPtr() const
std::optional< unsigned > getDeclID() const
Returns the declaration ID.
bool isField() const
Checks if the item is a field in an object.
unsigned getByteOffset() const
Returns the byte offset from the start.
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.
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B)
bool Interpret(InterpState &S, APValue &Result)
Interpreter entry point.
static bool runRecordDestructor(InterpState &S, CodePtr OpPC, const Pointer &BasePtr, const Descriptor *Desc)
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 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 CheckCallDepth(InterpState &S, CodePtr OpPC)
Checks if calling the currently active function would exceed the allowed call depth.
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks the 'this' pointer.
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Checks if the Descriptor is of a constexpr or const global variable.
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to a mutable field.
bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if Ptr is a one-past-the-end pointer.
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a value can be loaded from a block.
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is in range.
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD)
Checks if a method is pure virtual.
bool This(InterpState &S, CodePtr OpPC)
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 CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
This is not used by any of the opcodes directly.
static void popArg(InterpState &S, const Expr *Arg)
void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, const APSInt &Value)
PrimType
Enumeration of the primitive types of the VM.
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 CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Check if a global variable is initialized.
bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *CE, unsigned ArgSize)
Checks if all the arguments annotated as 'nonnull' are in fact not null.
bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is a dummy pointer.
void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC)
bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
llvm::BitVector collectNonNullArgs(const FunctionDecl *F, const llvm::ArrayRef< const Expr * > &Args)
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the variable has externally defined storage.
bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray, bool DeleteIsArray, const Descriptor *D, const Expr *NewExpr)
Diagnose mismatched new[]/delete or new/delete[] pairs.
bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F)
Checks if a method can be called.
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to const storage.
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a method can be invoked on an object.
bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, APFloat::opStatus Status)
Checks if the result of a floating-point operation is valid in the current context.
The JSON file list parser is used to communicate input to InstallAPI.
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 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.
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.