24#include "llvm/ADT/APSInt.h"
25#include "llvm/ADT/StringExtras.h"
35 llvm::report_fatal_error(
"Interpreter cannot return values");
48 if (S.Stk.pop<
bool>()) {
55 if (!S.Stk.pop<
bool>()) {
64 S.FFDiag(
E, diag::note_constexpr_var_init_unknown, 1) << VD;
74 if (isa<ParmVarDecl>(
D)) {
76 S.FFDiag(
E, diag::note_constexpr_function_param_value_unknown) <<
D;
84 if (!
D->getType().isConstQualified())
86 else if (
const auto *VD = dyn_cast<VarDecl>(
D);
87 VD && !VD->getAnyInitializer())
99 if (
const auto *VarD = dyn_cast<VarDecl>(VD);
100 VarD && VarD->getType().isConstQualified() &&
101 !VarD->getAnyInitializer()) {
108 if (isa<ObjCIvarDecl>(VD))
112 S.FFDiag(
Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;
118 S.
getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr
119 : diag::note_constexpr_ltor_non_integral,
135 while (!
U.isActive()) {
140 const Record *R =
U.getRecord();
141 assert(R && R->
isUnion() &&
"Not a union");
143 for (
unsigned I = 0, N = R->
getNumFields(); I < N; ++I) {
145 if (Field.isActive()) {
146 ActiveField = Field.getField();
152 S.FFDiag(
Loc, diag::note_constexpr_access_inactive_union_member)
153 << AK << InactiveField << !ActiveField << ActiveField;
166 if (S.P.getCurrentDecl() == ID)
170 S.FFDiag(
E, diag::note_constexpr_access_static_temporary, 1) << AK;
171 S.Note(Ptr.
getDeclLoc(), diag::note_constexpr_temporary_here);
182 if (S.P.getCurrentDecl() == ID)
185 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
200 const Function *CurFunc = S.Current->getFunction();
210 cast<CallExpr>(S.Current->Caller->getExpr(S.Current->getRetPC()));
211 for (int32_t I = CE->getNumArgs() - 1; I >= 0; --I) {
212 const Expr *A = CE->getArg(I);
218 if (S.Current->Caller && CurFunc->
isVariadic()) {
223 const Expr *
const *Args =
nullptr;
224 unsigned NumArgs = 0;
225 const Expr *CallSite = S.Current->Caller->getExpr(S.Current->getRetPC());
226 if (
const auto *CE = dyn_cast<CallExpr>(CallSite)) {
227 Args = CE->getArgs();
228 NumArgs = CE->getNumArgs();
229 }
else if (
const auto *CE = dyn_cast<CXXConstructExpr>(CallSite)) {
230 Args = CE->getArgs();
231 NumArgs = CE->getNumArgs();
233 assert(
false &&
"Can't get arguments from that expression type");
237 isa<CXXOperatorCallExpr>(CallSite));
238 for (
unsigned I = 0; I != NumVarArgs; ++I) {
239 const Expr *A = Args[NumArgs - 1 - I];
246 S.Current->popArgs();
257 if (!S.checkingPotentialConstantExpression() && S.
getLangOpts().CPlusPlus) {
268 S.FFDiag(
E, diag::note_constexpr_unsized_array_indexed);
275 const auto &Src = S.Current->getSource(OpPC);
278 S.FFDiag(Src, diag::note_constexpr_null_subobject) <<
CSK_Field;
280 S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
286 const auto &Src = S.Current->getSource(OpPC);
289 S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
292 S.Note(Ptr.
getDeclLoc(), diag::note_constexpr_temporary_here);
294 S.Note(Ptr.
getDeclLoc(), diag::note_declared_at);
305 auto IsConstType = [&S](
const VarDecl *VD) ->
bool {
306 if (VD->isConstexpr())
313 T.isConstQualified();
315 if (
T.isConstQualified())
322 return PT->getPointeeType().isConstQualified();
328 D &&
D->hasGlobalStorage() &&
D != S.EvaluatingDecl && !IsConstType(
D)) {
330 return S.inConstantContext();
347 S.FFDiag(
Loc, diag::note_constexpr_null_subobject)
348 << CSK << S.Current->getRange(OpPC);
358 S.FFDiag(
Loc, diag::note_constexpr_access_past_end)
359 << AK << S.Current->getRange(OpPC);
368 S.FFDiag(
Loc, diag::note_constexpr_past_end_subobject)
369 << CSK << S.Current->getRange(OpPC);
379 S.FFDiag(
Loc, diag::note_constexpr_past_end_subobject)
380 << CSK << S.Current->getRange(OpPC);
391 if (Offset < PtrOffset && (PtrOffset - Offset) >= MinOffset)
394 const auto *
E = cast<CastExpr>(S.Current->getExpr(OpPC));
398 S.CCEDiag(
E, diag::note_constexpr_invalid_downcast)
399 << MostDerivedQT << TargetQT;
405 assert(Ptr.
isLive() &&
"Pointer is not live");
413 if (S.Current->getFunction()) {
416 Func && (
Func->isConstructor() ||
Func->isDestructor()) &&
428 S.FFDiag(
Loc, diag::note_constexpr_modify_const_type) << Ty;
433 assert(Ptr.
isLive() &&
"Pointer is not live");
445 S.FFDiag(
Loc, diag::note_constexpr_access_mutable, 1) <<
AK_Read << Field;
446 S.Note(Field->getLocation(), diag::note_declared_at);
465 S.FFDiag(
Loc, diag::note_constexpr_access_volatile_type) << AK << PtrType;
481 if (VD->getAnyInitializer()) {
482 S.FFDiag(
Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
483 S.Note(VD->getLocation(), diag::note_declared_at);
490 if (!S.checkingPotentialConstantExpression()) {
491 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
492 << AK <<
true << S.Current->getRange(OpPC);
503 if ((!VD->hasConstantInitialization() &&
504 VD->mightBeUsableInConstantExpressions(S.getCtx())) ||
506 !VD->hasICEInitializer(S.getCtx()))) {
508 S.FFDiag(
Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
509 S.Note(VD->getLocation(), diag::note_declared_at);
580 S.CCEDiag(
Loc, diag::note_constexpr_virtual_call);
602 const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
603 if (CD && CD->isInheritingConstructor()) {
604 const auto *Inherited = CD->getInheritedConstructor().getConstructor();
605 if (!Inherited->isConstexpr())
606 DiagDecl = CD = Inherited;
612 if (CD && CD->isInheritingConstructor()) {
613 S.FFDiag(
Loc, diag::note_constexpr_invalid_inhctor, 1)
614 << CD->getInheritedConstructor().getConstructor()->getParent();
615 S.Note(DiagDecl->
getLocation(), diag::note_declared_at);
622 S.checkingPotentialConstantExpression())
631 S.FFDiag(
Loc, diag::note_constexpr_invalid_function, 1)
633 S.Note(DiagDecl->
getLocation(), diag::note_declared_at);
636 S.FFDiag(
Loc, diag::note_invalid_subexpr_in_const_expr);
643 if ((S.Current->getDepth() + 1) > S.
getLangOpts().ConstexprCallDepth) {
644 S.FFDiag(S.Current->getSource(OpPC),
645 diag::note_constexpr_depth_limit_exceeded)
659 bool IsImplicit =
false;
660 if (
const auto *
E = dyn_cast_if_present<CXXThisExpr>(
Loc.asExpr()))
661 IsImplicit =
E->isImplicit();
664 S.FFDiag(
Loc, diag::note_constexpr_this) << IsImplicit;
675 S.FFDiag(
E, diag::note_constexpr_pure_virtual_call, 1) << MD;
681 APFloat::opStatus Status) {
689 S.CCEDiag(
E, diag::note_constexpr_float_arithmetic)
690 <<
true << S.Current->getRange(OpPC);
691 return S.noteUndefinedBehavior();
696 if (S.inConstantContext())
701 if ((Status & APFloat::opInexact) &&
705 S.FFDiag(
E, diag::note_constexpr_dynamic_rounding);
709 if ((Status != APFloat::opOK) &&
712 FPO.getAllowFEnvAccess())) {
713 S.FFDiag(
E, diag::note_constexpr_float_arithmetic_strict);
717 if ((Status & APFloat::opStatus::opInvalidOp) &&
732 S.CCEDiag(
E, diag::note_constexpr_new);
738 const Expr *NewExpr) {
739 if (NewWasArray == DeleteIsArray)
747 QualType ElemQT =
D->getType()->getPointeeType();
748 TypeToDiagnose = S.getCtx().getConstantArrayType(
749 ElemQT,
APInt(64,
static_cast<uint64_t
>(
D->getNumElems()),
false),
752 TypeToDiagnose =
D->getType()->getPointeeType();
755 S.FFDiag(
E, diag::note_constexpr_new_delete_mismatch)
756 << DeleteIsArray << 0 << TypeToDiagnose;
757 S.Note(NewExpr->
getExprLoc(), diag::note_constexpr_dynamic_alloc_here)
764 if (Source && isa<CXXNewExpr>(Source))
769 S.FFDiag(
Loc, diag::note_constexpr_delete_not_heap_alloc)
773 S.Note(Ptr.
getDeclLoc(), diag::note_constexpr_temporary_here);
775 S.Note(Ptr.
getDeclLoc(), diag::note_declared_at);
802 S.FFDiag(
E, diag::note_constexpr_modify_global);
808 const CallExpr *CE,
unsigned ArgSize) {
813 for (
const Expr *Arg : Args) {
814 if (NonNullArgs[Index] && Arg->getType()->isPointerType()) {
818 S.CCEDiag(
Loc, diag::note_non_null_attribute_failed);
842 for (
const Record::Field &Field : llvm::reverse(R->
fields())) {
847 }
else if (
D->isCompositeArray()) {
850 for (
unsigned I = 0; I != Desc->
getNumElems(); ++I) {
861 const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor);
866 if (!
Call(S, OpPC, DtorFunc, 0))
871 for (
const Record::Base &
Base : llvm::reverse(R->
bases())) {
893 for (
unsigned I = 0; I != Desc->
getNumElems(); ++I) {
909 if (S.EvaluatingDecl && !S.EvaluatingDecl->isConstexpr())
918 S.report(
Loc, diag::warn_constexpr_unscoped_enum_out_of_range)
919 << llvm::toString(
Value, 10) <<
Min.getSExtValue() <<
Max.getSExtValue()
923 S.report(
Loc, diag::warn_constexpr_unscoped_enum_out_of_range)
924 << llvm::toString(
Value, 10) <<
Min.getZExtValue() <<
Max.getZExtValue()
935 assert(!S.Current->isRoot());
936 CodePtr PC = S.Current->getPC();
948#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.
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.
Pointer atField(unsigned Off) const
Creates a pointer to a field.
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.
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.
const Field * getField(const FieldDecl *FD) const
Returns a field.
llvm::iterator_range< const_base_iter > bases() const
unsigned getNumFields() const
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.
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.