16#include "llvm/ADT/ScopeExit.h"
23 : Ctx(Ctx), P(P), S(Settings, P, Stk, FA, Ctx, this), EvalResult(Ctx),
24 ConstexprKind(Settings.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();
151 bool IsConstexprUnknown) {
165 unsigned Off = Locals.size();
166 Locals.push_back(Memory);
173 if (S.Stk.pop<
bool>())
182 if (!S.Stk.pop<
bool>())
191 CurrentLabel = ActiveLabel = Label;
199 CurrentLabel = Label;
210 size_t StackSizeBefore = S.Stk.size();
212 if (!this->
visit(Arg)) {
213 S.Stk.clearTo(StackSizeBefore);
215 if (S.inConstantContext() || Arg->
HasSideEffects(S.getASTContext()))
222 const auto &Ptr = S.Stk.pop<
Pointer>();
227 if (!this->emitPop(
T, E))
232template <PrimType OpType>
bool EvalEmitter::emitRet(
SourceInfo Info) {
241template <>
bool EvalEmitter::emitRet<PT_MemberPtr>(
SourceInfo Info) {
253template <>
bool EvalEmitter::emitRet<PT_Ptr>(
SourceInfo Info) {
260 return (*this->PtrCB)(S,
CodePtr(), Ptr);
269 if (Ptr.isFunctionPointer()) {
270 if (ConvertResultToRValue && Ptr.asFunctionPointer().Func->getDecl())
280 if (ConvertResultToRValue) {
284 if (!EvalResult.checkLValueFields(S, Ptr, Info, ConstexprKind))
287 if (std::optional<APValue>
V =
288 Ptr.toRValue(Ctx, EvalResult.getSourceType())) {
289 EvalResult.takeValue(std::move(*
V));
296 if (!EvalResult.checkLValue(S, Ptr, Info, ConstexprKind))
299 if (!
Ptr.isLive() && !
Ptr.isTemporary())
302 if (
const Descriptor *DeclDesc =
Ptr.getDeclDesc();
303 DeclDesc && S.EvaluatingDecl &&
304 ((DeclDesc->asVarDecl() == S.EvaluatingDecl &&
305 S.getLangOpts().CPlusPlus23 &&
306 S.EvaluatingDecl->getType()->isReferenceType()) ||
307 Ptr.isConstexprUnknown())) {
308 S.FFDiag(Info, diag::note_constexpr_var_init_non_constant, 1)
309 << DeclDesc->asVarDecl();
310 S.Note(DeclDesc->asVarDecl()->getLocation(), diag::note_declared_at);
316 EvalResult.takeValue(std::move(
V));
320bool EvalEmitter::emitRetVoid(
SourceInfo Info) {
321 EvalResult.setValid();
325bool EvalEmitter::emitRetValue(
SourceInfo Info) {
328 if (!EvalResult.checkDynamicAllocations(S, Ptr, Info))
330 if (!EvalResult.checkFullyInitialized(S, Ptr))
332 if (!EvalResult.checkLValueFields(S, Ptr, Info, ConstexprKind))
335 if (std::optional<APValue> APV =
336 Ptr.toRValue(Ctx, EvalResult.getSourceType())) {
337 EvalResult.takeValue(std::move(*APV));
341 EvalResult.setInvalid();
349 Block *B = getLocal(I);
358 Block *B = getLocal(I);
362template <PrimType OpType>
367 using T =
typename PrimConv<OpType>::T;
369 Block *B = getLocal(I);
378template <PrimType OpType>
383 using T =
typename PrimConv<OpType>::T;
385 Block *B = getLocal(I);
386 B->
deref<
T>() = S.Stk.pop<
T>();
388 Desc.IsInitialized =
true;
410 Block *B = getLocal(I);
411 const auto &Desc = B->
getBlockDesc<LocalInlineDescriptor>();
413 S.Stk.push<
bool>(Desc.IsEnabled);
421 Block *B = getLocal(I);
423 Desc.IsEnabled =
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
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.
static unsigned allocSize(const Descriptor *D, BlockKind K)
Number of bytes needed to allocate the block.
Pointer into the code segment.
Holds all information required to evaluate constexpr code in a module.
ASTContext & getASTContext() const
Returns the AST context.
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.
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)
EvalEmitter(Context &Ctx, Program &P, const EvalSettings &Settings, InterpStack &Stk, FrameAllocator &FrameAlloc)
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.
Local createLocal(const Descriptor *D, bool IsConstexprUnknown=false)
Callback for registering a local.
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.
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)
@ Result
The result type of a method or function.
OptionalUnsigned< unsigned > UnsignedOrNone
const FunctionProtoType * T
@ Off
Never emit colors regardless of the output stream.
EvalStatus is a struct with detailed info about an evaluation in progress.
constexpr BlockFlags withConstexprUnknown(bool B=true) const
Describes a memory block created by an allocation site.
Mapping from primitive types to their representation.
Information about a local's storage.