24#include "llvm/ADT/APSInt.h"
30 llvm::report_fatal_error(
"Interpreter cannot return values");
43 if (S.Stk.pop<
bool>()) {
50 if (!S.Stk.pop<
bool>()) {
66 while (!
U.isActive()) {
71 const Record *R =
U.getRecord();
72 assert(R && R->
isUnion() &&
"Not a union");
74 for (
unsigned I = 0, N = R->
getNumFields(); I < N; ++I) {
76 if (Field.isActive()) {
77 ActiveField = Field.getField();
82 const SourceInfo &Loc = S.Current->getSource(OpPC);
83 S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)
84 << AK << InactiveField << !ActiveField << ActiveField;
97 if (S.P.getCurrentDecl() == ID)
100 const SourceInfo &E = S.Current->getSource(OpPC);
101 S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
102 S.Note(Ptr.
getDeclLoc(), diag::note_constexpr_temporary_here);
113 if (S.P.getCurrentDecl() == ID)
116 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
131 const Function *CurFunc = S.Current->getFunction();
137 if (S.Current->Caller && CurFunc->
isVariadic()) {
142 cast<CallExpr>(S.Current->Caller->getExpr(S.Current->getRetPC()));
144 int32_t ArgsToPop = CE->getNumArgs() - FixedParams;
145 assert(ArgsToPop >= 0);
146 for (int32_t I = ArgsToPop - 1; I >= 0; --I) {
147 const Expr *A = CE->getArg(FixedParams + I);
153 S.Current->popArgs();
160 if (!S.checkingPotentialConstantExpression() && S.
getLangOpts().CPlusPlus) {
162 const SourceInfo &Loc = S.Current->getSource(OpPC);
163 S.FFDiag(Loc, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
164 S.Note(VD->getLocation(), diag::note_declared_at);
172 const SourceInfo &E = S.Current->getSource(OpPC);
173 S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);
180 const auto &Src = S.Current->getSource(OpPC);
183 S.FFDiag(Src, diag::note_constexpr_null_subobject) <<
CSK_Field;
185 S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
191 const auto &Src = S.Current->getSource(OpPC);
194 S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
197 S.Note(Ptr.
getDeclLoc(), diag::note_constexpr_temporary_here);
199 S.Note(Ptr.
getDeclLoc(), diag::note_declared_at);
215 const SourceInfo &Loc = S.Current->getSource(OpPC);
216 S.FFDiag(Loc, diag::note_constexpr_null_subobject) << CSK;
224 const SourceInfo &Loc = S.Current->getSource(OpPC);
225 S.FFDiag(Loc, diag::note_constexpr_access_past_end) << AK;
233 const SourceInfo &Loc = S.Current->getSource(OpPC);
234 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK;
243 const SourceInfo &Loc = S.Current->getSource(OpPC);
244 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK;
249 assert(Ptr.
isLive() &&
"Pointer is not live");
256 Func && (
Func->isConstructor() ||
Func->isDestructor()) &&
257 Ptr.
block() == S.Current->getThis().block()) {
262 const SourceInfo &Loc = S.Current->getSource(OpPC);
263 S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
268 assert(Ptr.
isLive() &&
"Pointer is not live");
273 const SourceInfo &Loc = S.Current->getSource(OpPC);
275 S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) <<
AK_Read << Field;
276 S.Note(Field->getLocation(), diag::note_declared_at);
285 if (!S.checkingPotentialConstantExpression()) {
286 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
287 << AK <<
true << S.Current->getRange(OpPC);
348 S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
355 if (S.checkingPotentialConstantExpression())
364 const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
365 if (CD && CD->isInheritingConstructor()) {
366 const auto *Inherited = CD->getInheritedConstructor().getConstructor();
367 if (!Inherited->isConstexpr())
368 DiagDecl = CD = Inherited;
374 if (CD && CD->isInheritingConstructor())
375 S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)
376 << CD->getInheritedConstructor().getConstructor()->getParent();
378 S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
380 S.Note(DiagDecl->
getLocation(), diag::note_declared_at);
382 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
391 if ((S.Current->getDepth() + 1) > S.
getLangOpts().ConstexprCallDepth) {
392 S.FFDiag(S.Current->getSource(OpPC),
393 diag::note_constexpr_depth_limit_exceeded)
405 const SourceInfo &Loc = S.Current->getSource(OpPC);
407 bool IsImplicit =
false;
408 if (
const auto *E = dyn_cast_if_present<CXXThisExpr>(Loc.
asExpr()))
409 IsImplicit = E->isImplicit();
412 S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit;
422 const SourceInfo &E = S.Current->getSource(OpPC);
423 S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD;
430 assert(SubObjDecl &&
"Subobject declaration does not exist");
431 S.FFDiag(SI, diag::note_constexpr_uninitialized)
434 diag::note_constexpr_subobject_declared_here);
444 size_t NumElems = CAT->
getSize().getZExtValue();
449 for (
size_t I = 0; I != NumElems; ++I) {
453 }
else if (
const auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) {
454 for (
size_t I = 0; I != NumElems; ++I) {
459 for (
size_t I = 0; I != NumElems; ++I) {
478 QualType FieldType = F.Decl->getType();
497 if (!
P.isInitialized()) {
499 diag::note_constexpr_uninitialized_base)
500 << B.Desc->getType();
512 assert(!
This.isZero());
516 cast<ConstantArrayType>(
This.getType()->getAsArrayTypeUnsafe());
522 if (!S.inConstantContext())
525 const SourceInfo &E = S.Current->getSource(OpPC);
526 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
527 << 2 << S.
getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
532 APFloat::opStatus Status) {
533 const SourceInfo &E = S.Current->getSource(OpPC);
540 S.CCEDiag(E, diag::note_constexpr_float_arithmetic)
541 <<
true << S.Current->getRange(OpPC);
542 return S.noteUndefinedBehavior();
547 if (S.inConstantContext())
552 if ((Status & APFloat::opInexact) &&
556 S.FFDiag(E, diag::note_constexpr_dynamic_rounding);
560 if ((Status != APFloat::opOK) &&
563 FPO.getAllowFEnvAccess())) {
564 S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
568 if ((Status & APFloat::opStatus::opInvalidOp) &&
582 const SourceInfo &E = S.Current->getSource(OpPC);
584 if (isa<ParmVarDecl>(D)) {
586 S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D;
591 }
else if (
const auto *VD = dyn_cast<VarDecl>(D)) {
592 if (!VD->getType().isConstQualified()) {
594 VD->getType()->isIntegralOrEnumerationType()
595 ? diag::note_constexpr_ltor_non_const_int
596 : diag::note_constexpr_ltor_non_constexpr,
599 S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();
604 if (!VD->getAnyInitializer()) {
605 S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;
606 S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();
620 assert(!S.Current->isRoot());
621 CodePtr PC = S.Current->getPC();
633#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 bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result)
static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset)
#define TYPE_SWITCH(Expr, B)
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
QualType getElementType() const
Represents a static or instance method of a struct/union/class.
Represents the canonical version of C arrays with a specified constant size.
const llvm::APInt & getSize() const
A reference to a declared variable, function, enum, etc.
SourceLocation getLocation() const
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
This represents one expression.
FPOptions getFPFeaturesInEffect(const LangOptions &LO) const
Returns the set of floating point options that apply to this expression.
LangOptions::FPExceptionModeKind getExceptionMode() const
RoundingMode getRoundingMode() const
Represents a member of a struct/union/class.
Represents a function declaration or definition.
bool isPure() const
Whether this virtual function is pure, i.e.
bool isConstexpr() const
Whether this is a (C++11) constexpr function or constexpr constructor.
@ FPE_Ignore
Assume that floating-point exceptions are masked.
A (possibly-)qualified type.
bool isConstQualified() const
Determine whether this type is const-qualified.
const LangOptions & getLangOpts() const
Encodes a location in the source.
bool isIncompleteArrayType() const
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
bool isRecordType() const
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Pointer into the code segment.
std::enable_if_t<!std::is_pointer< T >::value, T > read()
Reads data and advances the pointer.
unsigned getNumParams() const
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
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.
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.
bool isDummy() const
Checks if the pointer pointers to a dummy value.
bool isExtern() const
Checks if the storage is extern.
Pointer atIndex(unsigned Idx) const
Offsets a pointer inside 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.
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.
bool isZero() const
Checks if the pointer is null.
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
const Record * getElemRecord() const
Returns the element record type, if this is a non-primive array.
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 isTemporary() const
Checks if the storage is temporary.
SourceLocation getDeclLoc() const
const Block * block() const
std::optional< unsigned > getDeclID() const
Returns the declaration ID.
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 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.
const Expr * asExpr() const
bool CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if reinterpret casts are legal in the current context.
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
bool Interpret(InterpState &S, APValue &Result)
Interpreter entry point.
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 CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks that all fields are initialized after a constructor call.
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 CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
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 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)
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 CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be loaded from a block.
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC, const Pointer &BasePtr, const Record *R)
void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC)
static void DiagnoseUninitializedSubobject(InterpState &S, const SourceInfo &SI, const FieldDecl *SubObjDecl)
static bool CheckArrayInitialized(InterpState &S, CodePtr OpPC, const Pointer &BasePtr, const ConstantArrayType *CAT)
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the variable has externally defined storage.
bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F)
Checks if a method can be called.
bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer is a dummy pointer.
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.
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 ValueDecl * asValueDecl() const
const Decl * asDecl() const
Describes a record field.