15#include "llvm/ADT/ScopeExit.h"
22 : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx) {}
25 for (
auto &
V : Locals) {
38 bool ConvertResultToRValue,
39 bool DestroyToplevelScope) {
43 EvalResult.setSource(E);
45 if (!this->
visitExpr(E, DestroyToplevelScope)) {
48 EvalResult.setInvalid();
51 return std::move(this->EvalResult);
55 bool CheckFullyInitialized) {
58 this->CheckFullyInitialized = CheckFullyInitialized;
59 S.EvaluatingDecl = VD;
61 EvalResult.setSource(VD);
64 this->ConvertResultToRValue = !
Init->isGLValue() && !T->isPointerType() &&
65 !T->isObjCObjectPointerType();
66 EvalResult.setSource(VD);
69 EvalResult.setInvalid();
71 S.EvaluatingDecl =
nullptr;
72 updateGlobalTemporaries();
73 return std::move(this->EvalResult);
80 S.EvaluatingDecl = VD;
82 EvalResult.setSource(VD);
85 EvalResult.setInvalid();
87 S.EvaluatingDecl =
nullptr;
88 return std::move(this->EvalResult);
94 this->ConvertResultToRValue =
false;
95 this->CheckFullyInitialized =
false;
97 EvalResult.setSource(E);
102 EvalResult.setInvalid();
105 return std::move(this->EvalResult);
111 this->ConvertResultToRValue =
false;
112 this->CheckFullyInitialized =
false;
114 EvalResult.setSource(E);
117 EvalResult.setInvalid();
119 return std::move(this->EvalResult);
126 this->
Params.insert({PD, {0,
false}});
139 if (EvalResult.empty() || EvalResult.isInvalid())
142 assert(!EvalResult.empty());
146 return Result.getInt().getBoolValue();
156 auto *B =
new (Memory.get())
Block(Ctx.getEvalID(), D,
false);
157 B->invokeCtorNoMemset();
163 Desc.IsActive =
false;
165 Desc.IsFieldMutable =
false;
167 Desc.IsInitialized =
false;
170 unsigned Off = Locals.size();
171 Locals.push_back(std::move(Memory));
178 if (S.Stk.pop<
bool>())
187 if (!S.Stk.pop<
bool>())
196 CurrentLabel = ActiveLabel = Label;
204 CurrentLabel = Label;
215 size_t StackSizeBefore = S.Stk.size();
217 if (!this->
visit(Arg)) {
218 S.Stk.clearTo(StackSizeBefore);
220 if (S.inConstantContext() || Arg->
HasSideEffects(S.getASTContext()))
227 const auto &Ptr = S.Stk.pop<
Pointer>();
232 if (!this->emitPop(T, E))
237template <PrimType OpType>
bool EvalEmitter::emitRet(
SourceInfo Info) {
246template <>
bool EvalEmitter::emitRet<PT_Ptr>(
SourceInfo Info) {
253 return (*this->PtrCB)(S, OpPC, Ptr);
267 if (ConvertResultToRValue) {
283 if (std::optional<APValue>
V =
285 EvalResult.takeValue(std::move(*
V));
294 EvalResult.takeValue(Ptr.
toAPValue(Ctx.getASTContext()));
304 if (
const Descriptor *DeclDesc = Ptr.
getDeclDesc();
305 DeclDesc && S.EvaluatingDecl &&
306 DeclDesc->
asVarDecl() == S.EvaluatingDecl &&
308 S.EvaluatingDecl->getType()->isReferenceType()) {
309 V.setConstexprUnknown(
true);
311 EvalResult.takeValue(std::move(
V));
317bool EvalEmitter::emitRetVoid(
SourceInfo Info) {
318 EvalResult.setValid();
322bool EvalEmitter::emitRetValue(
SourceInfo Info) {
323 const auto &Ptr = S.Stk.pop<
Pointer>();
325 if (!EvalResult.checkDynamicAllocations(S, Ctx, Ptr, Info))
327 if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
330 if (std::optional<APValue> APV =
331 Ptr.
toRValue(Ctx, EvalResult.getSourceType())) {
332 EvalResult.takeValue(std::move(*APV));
336 EvalResult.setInvalid();
344 Block *B = getLocal(I);
345 S.Stk.push<
Pointer>(B,
sizeof(InlineDescriptor));
353 Block *B = getLocal(I);
357template <PrimType OpType>
362 using T =
typename PrimConv<OpType>::T;
364 Block *B = getLocal(I);
369 S.Stk.push<T>(B->
deref<T>());
373template <PrimType OpType>
378 using T =
typename PrimConv<OpType>::T;
380 Block *B = getLocal(I);
381 B->
deref<T>() = S.Stk.pop<T>();
383 Desc.IsInitialized =
true;
405 Block *B = getLocal(I);
408 S.Stk.push<
bool>(Desc.IsActive);
421 Block *B = getLocal(I);
423 Desc.IsActive =
true;
432void EvalEmitter::updateGlobalTemporaries() {
433 for (
const auto &[E, Temp] : S.SeenGlobalTemporaries) {
436 const Pointer &Ptr = P.getPtrGlobal(*GlobalIndex);
437 APValue *Cached = Temp->getOrCreateValue(
true);
439 QualType TempType = E->
getType();
440 if (
const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
441 TempType = MTE->getSubExpr()->skipRValueSubobjectAdjustments()->getType();
443 if (OptPrimType T = Ctx.classify(TempType)) {
445 { *Cached = Ptr.
deref<T>().toAPValue(Ctx.getASTContext()); });
447 if (std::optional<APValue> APV = Ptr.
toRValue(Ctx, TempType))
451 S.SeenGlobalTemporaries.clear();
459#include "Opcodes.inc"
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
static bool CheckFullyInitialized(EvalInfo &Info, SourceLocation DiagLoc, QualType Type, const APValue &Value)
Check that this evaluated value is fully-initialized and can be loaded by an lvalue-to-rvalue convers...
#define TYPE_SWITCH(Expr, B)
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
SourceLocation getLocation() const
const LangOptions & getLangOpts() const LLVM_READONLY
Helper to get the language options from the ASTContext.
This represents one expression.
bool HasSideEffects(const ASTContext &Ctx, bool IncludePossibleEffects=true) const
HasSideEffects - This routine returns true for all those expressions which have any effect other than...
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Represents a function declaration or definition.
ArrayRef< ParmVarDecl * > parameters() const
Represents a parameter to a function.
A (possibly-)qualified type.
Represents a variable declaration or definition.
A memory block, either on the stack or in the heap.
void invokeDtor()
Invokes the Destructor.
bool isStatic() const
Checks if the block has static storage duration.
bool isInitialized() const
Returns whether the data of this block has been initialized via invoking the Ctor func.
unsigned getEvalID() const
The Evaluation ID this block was created in.
Holds all information required to evaluate constexpr code in a module.
ASTContext & getASTContext() const
Returns the AST context.
unsigned getEvalID() const
llvm::DenseMap< const ParmVarDecl *, FuncParam > Params
Parameter indices.
EvaluationResult interpretDecl(const VarDecl *VD, const Expr *Init, bool CheckFullyInitialized)
EvaluationResult interpretDestructor(const VarDecl *VD, const APValue &Value)
EvaluationResult interpretExpr(const Expr *E, bool ConvertResultToRValue=false, bool DestroyToplevelScope=false)
bool jump(const LabelTy &Label, SourceInfo SI)
virtual bool visit(const Expr *E)=0
bool speculate(const CallExpr *E, const LabelTy &EndLabel)
Speculative execution.
std::optional< bool > interpretWithSubstitutions(const FunctionDecl *Callee, ArrayRef< const Expr * > Args, const Expr *This, const Expr *Condition)
virtual bool visitDtorCall(const VarDecl *VD, const APValue &Value)=0
bool jumpFalse(const LabelTy &Label, SourceInfo SI)
Local createLocal(Descriptor *D)
Callback for registering a local.
bool interpretCall(const FunctionDecl *FD, const Expr *E)
Interpret the given expression as if it was in the body of the given function, i.e.
void emitLabel(LabelTy Label)
Define a label.
bool isActive() const
Since expressions can only jump forward, predicated execution is used to deal with if-else statements...
virtual bool visitWithSubstitutions(const FunctionDecl *Callee, ArrayRef< const Expr * > Args, const Expr *This, const Expr *Condition)=0
EvaluationResult interpretAsLValuePointer(const Expr *E, PtrCallback PtrCB)
virtual bool visitExpr(const Expr *E, bool DestroyToplevelScope)=0
Methods implemented by the compiler.
bool fallthrough(const LabelTy &Label)
virtual bool visitDeclAndReturn(const VarDecl *VD, const Expr *Init, bool ConstantContext)=0
void cleanup()
Clean up all resources.
LabelTy getLabel()
Create a label.
EvaluationResult interpretAsPointer(const Expr *E, PtrCallback PtrCB)
Interpret the given Expr to a Pointer.
EvalEmitter(Context &Ctx, Program &P, State &Parent, InterpStack &Stk)
virtual bool emitBool(bool V, const Expr *E)=0
bool jumpTrue(const LabelTy &Label, SourceInfo SI)
Emits jumps.
llvm::SmallVector< SmallVector< Local, 8 >, 2 > Descriptors
Local descriptors.
virtual bool visitLValueExpr(const Expr *E, bool DestroyToplevelScope)=0
llvm::function_ref< bool(InterpState &S, CodePtr OpPC, const Pointer &)> PtrCallback
Defines the result of an evaluation.
QualType getSourceType() const
bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const
Check that all subobjects of the given pointer have been initialized.
bool checkDynamicAllocations(InterpState &S, const Context &Ctx, const Pointer &Ptr, SourceInfo Info)
Check that none of the blocks the given pointer (transitively) points to are dynamically allocated.
Stack frame storing temporaries and parameters.
T pop()
Returns the value from the top of the stack and removes it.
InterpStack & Stk
Temporary stack.
A pointer to a memory block, live or dead.
bool isConst() const
Checks if an object or a subfield is mutable.
T & deref() const
Dereferences the pointer, if it's live.
QualType getType() const
Returns the type of the innermost field.
bool pointsToStringLiteral() const
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
bool isLive() const
Checks if the pointer is live.
bool isZero() const
Checks if the pointer is null.
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
APValue toAPValue(const ASTContext &ASTCtx) const
Converts the pointer to an APValue.
bool isPastEnd() const
Checks if the pointer points past the end of the object.
bool isBlockPointer() const
std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const
Converts the pointer to an APValue that is an rvalue.
bool isTemporary() const
Checks if the storage is temporary.
const Block * block() const
bool isFunctionPointer() const
The program contains and links the bytecode for all functions.
Describes the statement/declaration an opcode was generated from.
Interface for the VM to interact with the AST walker's context.
bool PushIgnoreDiags(InterpState &S)
bool PopIgnoreDiags(InterpState &S)
bool handleReference(InterpState &S, CodePtr OpPC, Block *B)
bool CheckBCPResult(InterpState &S, const Pointer &Ptr)
bool This(InterpState &S, CodePtr OpPC)
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
This is not used by any of the opcodes directly.
PrimType
Enumeration of the primitive types of the VM.
bool Init(InterpState &S, CodePtr OpPC)
bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
@ Result
The result type of a method or function.
OptionalUnsigned< unsigned > UnsignedOrNone
@ Off
Never emit colors regardless of the output stream.
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 __packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 uint32_t
Describes a memory block created by an allocation site.
const bool IsConst
Flag indicating if the block is mutable.
unsigned getAllocSize() const
Returns the allocated size, including metadata.
const VarDecl * asVarDecl() const
Inline descriptor embedded in structures and arrays.
Mapping from primitive types to their representation.
Information about a local's storage.