clang: lib/AST/ByteCode/EvalEmitter.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

14

15using namespace clang;

17

20 : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx) {

21

23 new InterpFrame(S, nullptr, nullptr, CodePtr(), 0);

24}

25

27 for (auto &[K, V] : Locals) {

28 Block *B = reinterpret_cast<Block *>(V.get());

31 }

32}

33

34

35

36

38

40 bool ConvertResultToRValue,

41 bool DestroyToplevelScope) {

43 this->ConvertResultToRValue = ConvertResultToRValue && !isa(E);

44 this->CheckFullyInitialized = isa(E);

45 EvalResult.setSource(E);

46

47 if (!this->visitExpr(E, DestroyToplevelScope)) {

48

49

50 EvalResult.setInvalid();

51 }

52

53 return std::move(this->EvalResult);

54}

55

58 this->CheckFullyInitialized = CheckFullyInitialized;

60 EvalResult.setSource(VD);

61

64 this->ConvertResultToRValue = Init->isGLValue() && T->isPointerType() &&

66 } else

67 this->ConvertResultToRValue = false;

68

69 EvalResult.setSource(VD);

70

72 EvalResult.setInvalid();

73

75 updateGlobalTemporaries();

76 return std::move(this->EvalResult);

77}

78

80

82

84

85 auto Memory = std::make_unique<char[]>(sizeof(Block) + D->getAllocSize());

86 auto *B = new (Memory.get()) Block(Ctx.getEvalID(), D, false);

88

89

98

99

100 unsigned Off = Locals.size();

101 Locals.insert({Off, std::move(Memory)});

102 return {Off, D};

103}

104

107 if (S.Stk.pop<bool>())

108 ActiveLabel = Label;

109 }

110 return true;

111}

112

115 if (!S.Stk.pop<bool>())

116 ActiveLabel = Label;

117 }

118 return true;

119}

120

123 CurrentLabel = ActiveLabel = Label;

124 return true;

125}

126

129 ActiveLabel = Label;

130 CurrentLabel = Label;

131 return true;

132}

133

134template bool EvalEmitter::emitRet(const SourceInfo &Info) {

136 return true;

137

140 return true;

141}

142

143template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {

145 return true;

146

148

150 return false;

152 return false;

153

154

155 if (ConvertResultToRValue) {

157 return false;

158

161 return false;

162 }

163

164

165

168 return false;

169

170 if (std::optional V =

172 EvalResult.setValue(*V);

173 } else {

174 return false;

175 }

176 } else {

178 }

179

180 return true;

181}

182template <> bool EvalEmitter::emitRet<PT_FnPtr>(const SourceInfo &Info) {

184 return true;

185

186

188 return true;

189}

190

191bool EvalEmitter::emitRetVoid(const SourceInfo &Info) {

192 EvalResult.setValid();

193 return true;

194}

195

196bool EvalEmitter::emitRetValue(const SourceInfo &Info) {

198

200 return false;

202 return false;

203

204 if (std::optional APV =

206 EvalResult.setValue(*APV);

207 return true;

208 }

209

210 EvalResult.setInvalid();

211 return false;

212}

213

214bool EvalEmitter::emitGetPtrLocal(uint32_t I, const SourceInfo &Info) {

216 return true;

217

218 Block *B = getLocal(I);

220 return true;

221}

222

223template

224bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) {

226 return true;

227

229

230 Block *B = getLocal(I);

231 S.Stk.push<T>(*reinterpret_cast<T *>(B->data()));

232 return true;

233}

234

235template

236bool EvalEmitter::emitSetLocal(uint32_t I, const SourceInfo &Info) {

238 return true;

239

241

242 Block *B = getLocal(I);

243 *reinterpret_cast<T *>(B->data()) = S.Stk.pop<T>();

246

247 return true;

248}

249

250bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) {

252 return true;

253

257 }

258

259 return true;

260}

261

262

263

264

265

266

267void EvalEmitter::updateGlobalTemporaries() {

269 if (std::optional GlobalIndex = P.getGlobal(E)) {

271 APValue *Cached = Temp->getOrCreateValue(true);

272

276 } else {

277 if (std::optional APV =

278 Ptr.toRValue(Ctx, Temp->getTemporaryExpr()->getType()))

279 *Cached = *APV;

280 }

281 }

282 }

284}

285

286

287

288

289

290#define GET_EVAL_IMPL

291#include "Opcodes.inc"

292#undef GET_EVAL_IMPL

Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....

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],...

This represents one expression.

SourceLocation getExprLoc() const LLVM_READONLY

getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...

A (possibly-)qualified type.

bool isPointerType() const

bool isObjCObjectPointerType() const

Represents a variable declaration or definition.

const Expr * getAnyInitializer() const

Get the initializer for this variable, no matter which declaration it is attached to.

A memory block, either on the stack or in the heap.

void invokeDtor()

Invokes the Destructor.

std::byte * data()

Returns a pointer to the stored data.

void invokeCtor()

Invokes the constructor.

std::byte * rawData()

Returns a pointer to the raw data, including metadata.

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.

Pointer into the code segment.

Holds all information required to evaluate constexpr code in a module.

ASTContext & getASTContext() const

Returns the AST context.

std::optional< PrimType > classify(QualType T) const

Classifies a type.

unsigned getEvalID() const

bool jump(const LabelTy &Label)

EvaluationResult interpretDecl(const VarDecl *VD, bool CheckFullyInitialized)

EvaluationResult interpretExpr(const Expr *E, bool ConvertResultToRValue=false, bool DestroyToplevelScope=false)

bool jumpFalse(const LabelTy &Label)

Local createLocal(Descriptor *D)

Callback for registering a local.

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 visitExpr(const Expr *E, bool DestroyToplevelScope)=0

Methods implemented by the compiler.

bool fallthrough(const LabelTy &Label)

void cleanup()

Clean up all resources.

LabelTy getLabel()

Create a label.

EvalEmitter(Context &Ctx, Program &P, State &Parent, InterpStack &Stk)

virtual bool visitDeclAndReturn(const VarDecl *VD, bool ConstantContext)=0

llvm::SmallVector< SmallVector< Local, 8 >, 2 > Descriptors

Local descriptors.

bool jumpTrue(const LabelTy &Label)

Emits jumps.

Defines the result of an evaluation.

QualType getSourceType() const

bool checkReturnValue(InterpState &S, const Context &Ctx, const Pointer &Ptr, const SourceInfo &Info)

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.

Frame storing local variables.

Stack frame storing temporaries and parameters.

T pop()

Returns the value from the top of the stack and removes it.

void push(Tys &&...Args)

Constructs a value in place on the top of the stack.

ASTContext & getASTContext() const override

llvm::SmallVector< std::pair< const Expr *, const LifetimeExtendedTemporaryDecl * > > SeenGlobalTemporaries

InterpStack & Stk

Temporary stack.

const VarDecl * EvaluatingDecl

Declaration we're initializing/evaluting, if any.

InterpFrame * Current

The current frame.

void deallocate(Block *B)

Deallocates a pointer.

void setEvalLocation(SourceLocation SL)

bool inConstantContext() const

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.

bool isZero() const

Checks if the pointer is null.

APValue toAPValue(const ASTContext &ASTCtx) const

Converts the pointer to an APValue.

bool isDereferencable() const

Whether this block can be read from at all.

bool isBlockPointer() const

std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const

Converts the pointer to an APValue that is an rvalue.

const Block * block() const

The program contains and links the bytecode for all functions.

Block * getGlobal(unsigned Idx)

Returns the value of a global.

Pointer getPtrGlobal(unsigned Idx) const

Returns a pointer to a global.

Describes the statement/declaration an opcode was generated from.

Interface for the VM to interact with the AST walker's context.

const LangOptions & getLangOpts() const

bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)

This is not used by any of the opcodes directly.

The JSON file list parser is used to communicate input to InstallAPI.

const FunctionProtoType * T

Describes a memory block created by an allocation site.

Inline descriptor embedded in structures and arrays.

unsigned IsActive

Flag indicating if the field is the active member of a union.

unsigned IsBase

Flag indicating if the field is an embedded base class.

unsigned Offset

Offset inside the structure/array.

unsigned IsInitialized

For primitive fields, it indicates if the field was initialized.

unsigned IsConst

Flag indicating if the storage is constant or not.

unsigned IsFieldMutable

Flag indicating if the field is mutable (if in a record).

Mapping from primitive types to their representation.

Information about a local's storage.

unsigned Offset

Offset of the local in frame.