15#include "llvm/ADT/ScopeExit.h"
23 : Ctx(Ctx), P(P), S(Parent, P, Stk, FA, Ctx, this), EvalResult(Ctx),
24 ConstexprKind(ConstexprKind) {}
28 : Ctx(Ctx), P(P), S(Status, P, Stk, FA, Ctx, this), EvalResult(Ctx) {}
36 bool ConvertResultToRValue,
37 bool DestroyToplevelScope) {
41 EvalResult.setSource(E);
43 if (!this->
visitExpr(E, DestroyToplevelScope)) {
46 EvalResult.setInvalid();
49 return std::move(this->EvalResult);
53 bool CheckFullyInitialized) {
56 this->CheckFullyInitialized = CheckFullyInitialized;
57 S.EvaluatingDecl = VD;
59 EvalResult.setSource(VD);
62 this->ConvertResultToRValue = !
Init->isGLValue() && !
T->isPointerType() &&
63 !
T->isObjCObjectPointerType();
66 EvalResult.setInvalid();
68 S.EvaluatingDecl =
nullptr;
69 updateGlobalTemporaries();
70 return std::move(this->EvalResult);
77 S.EvaluatingDecl = VD;
79 EvalResult.setSource(VD);
82 EvalResult.setInvalid();
84 S.EvaluatingDecl =
nullptr;
85 return std::move(this->EvalResult);
91 this->ConvertResultToRValue =
false;
92 this->CheckFullyInitialized =
false;
94 EvalResult.setSource(E);
99 EvalResult.setInvalid();
102 return std::move(this->EvalResult);
108 this->ConvertResultToRValue =
false;
109 this->CheckFullyInitialized =
false;
111 EvalResult.setSource(E);
114 EvalResult.setInvalid();
116 return std::move(this->EvalResult);
123 this->
Params.insert({PD, {0,
false}});
136 if (EvalResult.empty() || EvalResult.isInvalid())
139 assert(!EvalResult.empty());
143 return Result.getInt().getBoolValue();
152 char *Memory =
reinterpret_cast<char *
>(
162 Desc.IsActive =
false;
164 Desc.IsFieldMutable =
false;
166 Desc.IsInitialized =
false;
169 unsigned Off = Locals.size();
170 Locals.push_back(Memory);
177 if (S.Stk.pop<
bool>())
186 if (!S.Stk.pop<
bool>())
195 CurrentLabel = ActiveLabel = Label;
203 CurrentLabel = Label;
214 size_t StackSizeBefore = S.Stk.size();
216 if (!this->
visit(Arg)) {
217 S.Stk.clearTo(StackSizeBefore);
219 if (S.inConstantContext() || Arg->
HasSideEffects(S.getASTContext()))
226 const auto &Ptr = S.Stk.pop<
Pointer>();
231 if (!this->emitPop(
T, E))
236template <PrimType OpType>
bool EvalEmitter::emitRet(
SourceInfo Info) {
245template <>
bool EvalEmitter::emitRet<PT_MemberPtr>(
SourceInfo Info) {
257template <>
bool EvalEmitter::emitRet<PT_Ptr>(
SourceInfo Info) {
264 return (*this->PtrCB)(S,
CodePtr(), Ptr);
273 if (Ptr.isFunctionPointer()) {
274 if (ConvertResultToRValue && Ptr.asFunctionPointer().Func->getDecl())
284 if (ConvertResultToRValue) {
293 if (!
Ptr.isZero() && !
Ptr.isConst() &&
Ptr.isBlockPointer() &&
294 Ptr.block()->getEvalID() != Ctx.getEvalID())
297 if (!EvalResult.checkLValueFields(S, Ptr, Info, ConstexprKind))
300 if (std::optional<APValue>
V =
301 Ptr.toRValue(Ctx, EvalResult.getSourceType())) {
302 EvalResult.takeValue(std::move(*
V));
309 if (!EvalResult.checkLValue(S, Ptr, Info, ConstexprKind))
312 if (!
Ptr.isLive() && !
Ptr.isTemporary())
315 if (
const Descriptor *DeclDesc =
Ptr.getDeclDesc();
316 DeclDesc && S.EvaluatingDecl &&
317 ((DeclDesc->asVarDecl() == S.EvaluatingDecl &&
318 S.getLangOpts().CPlusPlus23 &&
319 S.EvaluatingDecl->getType()->isReferenceType()) ||
320 DeclDesc->IsConstexprUnknown)) {
321 S.FFDiag(Info, diag::note_constexpr_var_init_non_constant, 1)
322 << DeclDesc->asVarDecl();
323 S.Note(DeclDesc->asVarDecl()->getLocation(), diag::note_declared_at);
329 EvalResult.takeValue(std::move(
V));
333bool EvalEmitter::emitRetVoid(
SourceInfo Info) {
334 EvalResult.setValid();
338bool EvalEmitter::emitRetValue(
SourceInfo Info) {
341 if (!EvalResult.checkDynamicAllocations(S, Ptr, Info))
343 if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
345 if (!EvalResult.checkLValueFields(S, Ptr, Info, ConstexprKind))
348 if (std::optional<APValue> APV =
349 Ptr.toRValue(Ctx, EvalResult.getSourceType())) {
350 EvalResult.takeValue(std::move(*APV));
354 EvalResult.setInvalid();
362 Block *B = getLocal(I);
363 S.Stk.push<
Pointer>(B,
sizeof(InlineDescriptor));
371 Block *B = getLocal(I);
375template <PrimType OpType>
380 using T =
typename PrimConv<OpType>::T;
382 Block *B = getLocal(I);
391template <PrimType OpType>
396 using T =
typename PrimConv<OpType>::T;
398 Block *B = getLocal(I);
399 B->
deref<
T>() = S.Stk.pop<
T>();
401 Desc.IsInitialized =
true;
423 Block *B = getLocal(I);
426 S.Stk.push<
bool>(Desc.IsActive);
439 Block *B = getLocal(I);
441 Desc.IsActive =
true;
450void EvalEmitter::updateGlobalTemporaries() {
451 for (
const auto &[E, Temp] : S.SeenGlobalTemporaries) {
454 const Pointer &
Ptr = P.getPtrGlobal(*GlobalIndex);
455 APValue *Cached = Temp->getOrCreateValue(
true);
457 QualType TempType = E->getType();
458 if (
const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
459 TempType = MTE->getSubExpr()->skipRValueSubobjectAdjustments()->getType();
461 if (OptPrimType
T = Ctx.classify(TempType)) {
463 { *Cached =
Ptr.deref<
T>().toAPValue(Ctx.getASTContext()); });
465 if (std::optional<APValue> APV =
Ptr.toRValue(Ctx, TempType))
469 S.SeenGlobalTemporaries.clear();
477#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
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.
static constexpr uint8_t InlineDescMD
Pointer into the code segment.
Holds all information required to evaluate constexpr code in a module.
ASTContext & getASTContext() const
Returns the AST context.
EvalEmitter(Context &Ctx, Program &P, State &Parent, InterpStack &Stk, FrameAllocator &FrameAlloc, ConstantExprKind ConstexprKind=ConstantExprKind::Normal)
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)
bool jump(const LabelTy &Label, SourceInfo SI)
virtual bool visit(const Expr *E)=0
bool speculate(const CallExpr *E, const LabelTy &EndLabel)
Speculative execution.
Local createLocal(const Descriptor *D)
Callback for registering a local.
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)
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.
EvaluationResult interpretExpr(const Expr *E)
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.
llvm::SmallVector< SmallVector< Local, 2 >, 1 > Descriptors
Local descriptors.
virtual bool emitBool(bool V, const Expr *E)=0
bool jumpTrue(const LabelTy &Label, SourceInfo SI)
Emits jumps.
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.
static bool checkMemberPointer(InterpState &S, const MemberPointer &MemberPtr, SourceInfo Info, ConstantExprKind ConstexprKind)
Check if the given member pointer can be returned from an evaluation.
bool checkFunctionPointer(InterpState &S, const Pointer &Ptr, SourceInfo Info, ConstantExprKind ConstexprKind) const
Check if the given function pointer can be returned from an evaluation.
bool checkDynamicAllocations(InterpState &S, const Pointer &Ptr, SourceInfo Info) const
Check that none of the blocks the given pointer (transitively) points to are dynamically allocated.
bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const
Check that all subobjects of the given pointer have been initialized.
Allocator for function frames.
Stack frame storing temporaries and parameters.
T pop()
Returns the value from the top of the stack and removes it.
InterpStack & Stk
Temporary stack.
APValue toAPValue(const ASTContext &) const
A pointer to a memory block, live or dead.
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)
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
Expr::ConstantExprKind ConstantExprKind
@ Result
The result type of a method or function.
OptionalUnsigned< unsigned > UnsignedOrNone
const FunctionProtoType * T
@ Off
Never emit colors regardless of the output stream.
__builtin_elementwise_add_sat __builtin_elementwise_sub_sat uint32_t __packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 __packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 uint32_t
EvalStatus is a struct with detailed info about an evaluation in progress.
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.
Inline descriptor embedded in structures and arrays.
Mapping from primitive types to their representation.
Information about a local's storage.