Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/AST/Interp/ByteCodeExprGen.h
Line
Count
Source (jump to first uncovered line)
1
//===--- ByteCodeExprGen.h - Code generator for expressions -----*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// Defines the constexpr bytecode compiler.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#ifndef LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
14
#define LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
15
16
#include "ByteCodeEmitter.h"
17
#include "EvalEmitter.h"
18
#include "Pointer.h"
19
#include "PrimType.h"
20
#include "Record.h"
21
#include "clang/AST/Decl.h"
22
#include "clang/AST/Expr.h"
23
#include "clang/AST/StmtVisitor.h"
24
#include "clang/Basic/TargetInfo.h"
25
26
namespace clang {
27
class QualType;
28
29
namespace interp {
30
31
template <class Emitter> class LocalScope;
32
template <class Emitter> class DestructorScope;
33
template <class Emitter> class RecordScope;
34
template <class Emitter> class VariableScope;
35
template <class Emitter> class DeclScope;
36
template <class Emitter> class OptionScope;
37
template <class Emitter> class ArrayIndexScope;
38
template <class Emitter> class SourceLocScope;
39
40
/// Compilation context for expressions.
41
template <class Emitter>
42
class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
43
                        public Emitter {
44
protected:
45
  // Aliases for types defined in the emitter.
46
  using LabelTy = typename Emitter::LabelTy;
47
  using AddrTy = typename Emitter::AddrTy;
48
49
  /// Current compilation context.
50
  Context &Ctx;
51
  /// Program to link to.
52
  Program &P;
53
54
public:
55
  /// Initializes the compiler and the backend emitter.
56
  template <typename... Tys>
57
  ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args)
58
0
      : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::ByteCodeExprGen<>(clang::interp::Context&, clang::interp::Program&)
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::ByteCodeExprGen<clang::interp::State&, clang::interp::InterpStack&, clang::APValue&>(clang::interp::Context&, clang::interp::Program&, clang::interp::State&, clang::interp::InterpStack&, clang::APValue&)
59
60
  // Expression visitors - result returned on interp stack.
61
  bool VisitCastExpr(const CastExpr *E);
62
  bool VisitIntegerLiteral(const IntegerLiteral *E);
63
  bool VisitFloatingLiteral(const FloatingLiteral *E);
64
  bool VisitParenExpr(const ParenExpr *E);
65
  bool VisitBinaryOperator(const BinaryOperator *E);
66
  bool VisitLogicalBinOp(const BinaryOperator *E);
67
  bool VisitPointerArithBinOp(const BinaryOperator *E);
68
  bool VisitComplexBinOp(const BinaryOperator *E);
69
  bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
70
  bool VisitCallExpr(const CallExpr *E);
71
  bool VisitBuiltinCallExpr(const CallExpr *E);
72
  bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E);
73
  bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);
74
  bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
75
  bool VisitGNUNullExpr(const GNUNullExpr *E);
76
  bool VisitCXXThisExpr(const CXXThisExpr *E);
77
  bool VisitUnaryOperator(const UnaryOperator *E);
78
  bool VisitDeclRefExpr(const DeclRefExpr *E);
79
  bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
80
  bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E);
81
  bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
82
  bool VisitInitListExpr(const InitListExpr *E);
83
  bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
84
  bool VisitConstantExpr(const ConstantExpr *E);
85
  bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
86
  bool VisitMemberExpr(const MemberExpr *E);
87
  bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E);
88
  bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);
89
  bool VisitOpaqueValueExpr(const OpaqueValueExpr *E);
90
  bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E);
91
  bool VisitStringLiteral(const StringLiteral *E);
92
  bool VisitCharacterLiteral(const CharacterLiteral *E);
93
  bool VisitCompoundAssignOperator(const CompoundAssignOperator *E);
94
  bool VisitFloatCompoundAssignOperator(const CompoundAssignOperator *E);
95
  bool VisitPointerCompoundAssignOperator(const CompoundAssignOperator *E);
96
  bool VisitExprWithCleanups(const ExprWithCleanups *E);
97
  bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
98
  bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E);
99
  bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
100
  bool VisitTypeTraitExpr(const TypeTraitExpr *E);
101
  bool VisitLambdaExpr(const LambdaExpr *E);
102
  bool VisitPredefinedExpr(const PredefinedExpr *E);
103
  bool VisitCXXThrowExpr(const CXXThrowExpr *E);
104
  bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E);
105
  bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);
106
  bool VisitCXXConstructExpr(const CXXConstructExpr *E);
107
  bool VisitSourceLocExpr(const SourceLocExpr *E);
108
  bool VisitOffsetOfExpr(const OffsetOfExpr *E);
109
  bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E);
110
  bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
111
112
protected:
113
  bool visitExpr(const Expr *E) override;
114
  bool visitDecl(const VarDecl *VD) override;
115
116
protected:
117
  /// Emits scope cleanup instructions.
118
  void emitCleanup();
119
120
  /// Returns a record type from a record or pointer type.
121
  const RecordType *getRecordTy(QualType Ty);
122
123
  /// Returns a record from a record or pointer type.
124
  Record *getRecord(QualType Ty);
125
  Record *getRecord(const RecordDecl *RD);
126
127
  // Returns a function for the given FunctionDecl.
128
  // If the function does not exist yet, it is compiled.
129
  const Function *getFunction(const FunctionDecl *FD);
130
131
  /// Classifies a type.
132
0
  std::optional<PrimType> classify(const Expr *E) const {
133
0
    if (E->isGLValue()) {
134
0
      if (E->getType()->isFunctionType())
135
0
        return PT_FnPtr;
136
0
      return PT_Ptr;
137
0
    }
138
139
0
    return classify(E->getType());
140
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::classify(clang::Expr const*) const
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::classify(clang::Expr const*) const
141
0
  std::optional<PrimType> classify(QualType Ty) const {
142
0
    return Ctx.classify(Ty);
143
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::classify(clang::QualType) const
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::classify(clang::QualType) const
144
145
  /// Classifies a known primitive type
146
0
  PrimType classifyPrim(QualType Ty) const {
147
0
    if (auto T = classify(Ty)) {
148
0
      return *T;
149
0
    }
150
0
    llvm_unreachable("not a primitive type");
151
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::classifyPrim(clang::QualType) const
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::classifyPrim(clang::QualType) const
152
  /// Evaluates an expression and places the result on the stack. If the
153
  /// expression is of composite type, a local variable will be created
154
  /// and a pointer to said variable will be placed on the stack.
155
  bool visit(const Expr *E);
156
  /// Compiles an initializer. This is like visit() but it will never
157
  /// create a variable and instead rely on a variable already having
158
  /// been created. visitInitializer() then relies on a pointer to this
159
  /// variable being on top of the stack.
160
  bool visitInitializer(const Expr *E);
161
  /// Evaluates an expression for side effects and discards the result.
162
  bool discard(const Expr *E);
163
  /// Just pass evaluation on to \p E. This leaves all the parsing flags
164
  /// intact.
165
  bool delegate(const Expr *E);
166
167
  /// Creates and initializes a variable from the given decl.
168
  bool visitVarDecl(const VarDecl *VD);
169
  /// Visit an APValue.
170
  bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E);
171
172
  /// Visits an expression and converts it to a boolean.
173
  bool visitBool(const Expr *E);
174
175
  /// Visits an initializer for a local.
176
0
  bool visitLocalInitializer(const Expr *Init, unsigned I) {
177
0
    if (!this->emitGetPtrLocal(I, Init))
178
0
      return false;
179
180
0
    if (!visitInitializer(Init))
181
0
      return false;
182
183
0
    return this->emitPopPtr(Init);
184
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::visitLocalInitializer(clang::Expr const*, unsigned int)
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::visitLocalInitializer(clang::Expr const*, unsigned int)
185
186
  /// Visits an initializer for a global.
187
0
  bool visitGlobalInitializer(const Expr *Init, unsigned I) {
188
0
    if (!this->emitGetPtrGlobal(I, Init))
189
0
      return false;
190
191
0
    if (!visitInitializer(Init))
192
0
      return false;
193
194
0
    if ((Init->getType()->isArrayType() || Init->getType()->isRecordType()) &&
195
0
        !this->emitCheckGlobalCtor(Init))
196
0
      return false;
197
198
0
    return this->emitPopPtr(Init);
199
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::visitGlobalInitializer(clang::Expr const*, unsigned int)
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::visitGlobalInitializer(clang::Expr const*, unsigned int)
200
201
  /// Visits a delegated initializer.
202
0
  bool visitThisInitializer(const Expr *I) {
203
0
    if (!this->emitThis(I))
204
0
      return false;
205
206
0
    if (!visitInitializer(I))
207
0
      return false;
208
209
0
    return this->emitPopPtr(I);
210
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::visitThisInitializer(clang::Expr const*)
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::visitThisInitializer(clang::Expr const*)
211
212
  bool visitInitList(ArrayRef<const Expr *> Inits, const Expr *E);
213
  bool visitArrayElemInit(unsigned ElemIndex, const Expr *Init);
214
215
  /// Creates a local primitive value.
216
  unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst,
217
                                  bool IsExtended = false);
218
219
  /// Allocates a space storing a local given its type.
220
  std::optional<unsigned> allocateLocal(DeclTy &&Decl, bool IsExtended = false);
221
222
private:
223
  friend class VariableScope<Emitter>;
224
  friend class LocalScope<Emitter>;
225
  friend class DestructorScope<Emitter>;
226
  friend class RecordScope<Emitter>;
227
  friend class DeclScope<Emitter>;
228
  friend class OptionScope<Emitter>;
229
  friend class ArrayIndexScope<Emitter>;
230
  friend class SourceLocScope<Emitter>;
231
232
  /// Emits a zero initializer.
233
  bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E);
234
  bool visitZeroRecordInitializer(const Record *R, const Expr *E);
235
236
  enum class DerefKind {
237
    /// Value is read and pushed to stack.
238
    Read,
239
    /// Direct method generates a value which is written. Returns pointer.
240
    Write,
241
    /// Direct method receives the value, pushes mutated value. Returns pointer.
242
    ReadWrite,
243
  };
244
245
  /// Method to directly load a value. If the value can be fetched directly,
246
  /// the direct handler is called. Otherwise, a pointer is left on the stack
247
  /// and the indirect handler is expected to operate on that.
248
  bool dereference(const Expr *LV, DerefKind AK,
249
                   llvm::function_ref<bool(PrimType)> Direct,
250
                   llvm::function_ref<bool(PrimType)> Indirect);
251
  bool dereferenceParam(const Expr *LV, PrimType T, const ParmVarDecl *PD,
252
                        DerefKind AK,
253
                        llvm::function_ref<bool(PrimType)> Direct,
254
                        llvm::function_ref<bool(PrimType)> Indirect);
255
  bool dereferenceVar(const Expr *LV, PrimType T, const VarDecl *PD,
256
                      DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
257
                      llvm::function_ref<bool(PrimType)> Indirect);
258
259
  /// Emits an APSInt constant.
260
  bool emitConst(const llvm::APSInt &Value, PrimType Ty, const Expr *E);
261
  bool emitConst(const llvm::APSInt &Value, const Expr *E);
262
0
  bool emitConst(const llvm::APInt &Value, const Expr *E) {
263
0
    return emitConst(static_cast<llvm::APSInt>(Value), E);
264
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::emitConst(llvm::APInt const&, clang::Expr const*)
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::emitConst(llvm::APInt const&, clang::Expr const*)
265
266
  /// Emits an integer constant.
267
  template <typename T> bool emitConst(T Value, PrimType Ty, const Expr *E);
268
  template <typename T> bool emitConst(T Value, const Expr *E);
269
270
  /// Returns the CXXRecordDecl for the type of the given expression,
271
  /// or nullptr if no such decl exists.
272
0
  const CXXRecordDecl *getRecordDecl(const Expr *E) const {
273
0
    QualType T = E->getType();
274
0
    if (const auto *RD = T->getPointeeCXXRecordDecl())
275
0
      return RD;
276
0
    return T->getAsCXXRecordDecl();
277
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::getRecordDecl(clang::Expr const*) const
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::getRecordDecl(clang::Expr const*) const
278
279
0
  llvm::RoundingMode getRoundingMode(const Expr *E) const {
280
0
    FPOptions FPO = E->getFPFeaturesInEffect(Ctx.getLangOpts());
281
282
0
    if (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic)
283
0
      return llvm::RoundingMode::NearestTiesToEven;
284
285
0
    return FPO.getRoundingMode();
286
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::getRoundingMode(clang::Expr const*) const
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::getRoundingMode(clang::Expr const*) const
287
288
  bool emitPrimCast(PrimType FromT, PrimType ToT, QualType ToQT, const Expr *E);
289
0
  std::optional<PrimType> classifyComplexElementType(QualType T) const {
290
0
    assert(T->isAnyComplexType());
291
292
0
    QualType ElemType = T->getAs<ComplexType>()->getElementType();
293
294
0
    return this->classify(ElemType);
295
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::classifyComplexElementType(clang::QualType) const
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::classifyComplexElementType(clang::QualType) const
296
297
  bool emitRecordDestruction(const Descriptor *Desc);
298
  unsigned collectBaseOffset(const RecordType *BaseType,
299
                             const RecordType *DerivedType);
300
301
protected:
302
  /// Variable to storage mapping.
303
  llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
304
305
  /// OpaqueValueExpr to location mapping.
306
  llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs;
307
308
  /// Current scope.
309
  VariableScope<Emitter> *VarScope = nullptr;
310
311
  /// Current argument index. Needed to emit ArrayInitIndexExpr.
312
  std::optional<uint64_t> ArrayIndex;
313
314
  /// DefaultInit- or DefaultArgExpr, needed for SourceLocExpr.
315
  const Expr *SourceLocDefaultExpr = nullptr;
316
317
  /// Flag indicating if return value is to be discarded.
318
  bool DiscardResult = false;
319
320
  /// Flag inidicating if we're initializing an already created
321
  /// variable. This is set in visitInitializer().
322
  bool Initializing = false;
323
324
  /// Flag indicating if we're initializing a global variable.
325
  bool GlobalDecl = false;
326
};
327
328
extern template class ByteCodeExprGen<ByteCodeEmitter>;
329
extern template class ByteCodeExprGen<EvalEmitter>;
330
331
/// Scope chain managing the variable lifetimes.
332
template <class Emitter> class VariableScope {
333
public:
334
  VariableScope(ByteCodeExprGen<Emitter> *Ctx)
335
0
      : Ctx(Ctx), Parent(Ctx->VarScope) {
336
0
    Ctx->VarScope = this;
337
0
  }
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::VariableScope(clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>*)
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::VariableScope(clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>*)
338
339
0
  virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::~VariableScope()
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::~VariableScope()
340
341
0
  void add(const Scope::Local &Local, bool IsExtended) {
342
0
    if (IsExtended)
343
0
      this->addExtended(Local);
344
0
    else
345
0
      this->addLocal(Local);
346
0
  }
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::add(clang::interp::Scope::Local const&, bool)
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::add(clang::interp::Scope::Local const&, bool)
347
348
0
  virtual void addLocal(const Scope::Local &Local) {
349
0
    if (this->Parent)
350
0
      this->Parent->addLocal(Local);
351
0
  }
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::addLocal(clang::interp::Scope::Local const&)
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::addLocal(clang::interp::Scope::Local const&)
352
353
0
  virtual void addExtended(const Scope::Local &Local) {
354
0
    if (this->Parent)
355
0
      this->Parent->addExtended(Local);
356
0
  }
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::addExtended(clang::interp::Scope::Local const&)
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::addExtended(clang::interp::Scope::Local const&)
357
358
0
  virtual void emitDestruction() {}
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::emitDestruction()
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::emitDestruction()
359
0
  virtual void emitDestructors() {}
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::emitDestructors()
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::emitDestructors()
360
0
  VariableScope *getParent() const { return Parent; }
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::getParent() const
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::getParent() const
361
362
protected:
363
  /// ByteCodeExprGen instance.
364
  ByteCodeExprGen<Emitter> *Ctx;
365
  /// Link to the parent scope.
366
  VariableScope *Parent;
367
};
368
369
/// Generic scope for local variables.
370
template <class Emitter> class LocalScope : public VariableScope<Emitter> {
371
public:
372
0
  LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {}
Unexecuted instantiation: clang::interp::LocalScope<clang::interp::ByteCodeEmitter>::LocalScope(clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>*)
Unexecuted instantiation: clang::interp::LocalScope<clang::interp::EvalEmitter>::LocalScope(clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>*)
373
374
  /// Emit a Destroy op for this scope.
375
0
  ~LocalScope() override {
376
0
    if (!Idx)
377
0
      return;
378
0
    this->Ctx->emitDestroy(*Idx, SourceInfo{});
379
0
  }
Unexecuted instantiation: clang::interp::LocalScope<clang::interp::ByteCodeEmitter>::~LocalScope()
Unexecuted instantiation: clang::interp::LocalScope<clang::interp::EvalEmitter>::~LocalScope()
380
381
  /// Overriden to support explicit destruction.
382
0
  void emitDestruction() override {
383
0
    if (!Idx)
384
0
      return;
385
0
    this->emitDestructors();
386
0
    this->Ctx->emitDestroy(*Idx, SourceInfo{});
387
0
    this->Idx = std::nullopt;
388
0
  }
Unexecuted instantiation: clang::interp::LocalScope<clang::interp::ByteCodeEmitter>::emitDestruction()
Unexecuted instantiation: clang::interp::LocalScope<clang::interp::EvalEmitter>::emitDestruction()
389
390
0
  void addLocal(const Scope::Local &Local) override {
391
0
    if (!Idx) {
392
0
      Idx = this->Ctx->Descriptors.size();
393
0
      this->Ctx->Descriptors.emplace_back();
394
0
    }
395
396
0
    this->Ctx->Descriptors[*Idx].emplace_back(Local);
397
0
  }
Unexecuted instantiation: clang::interp::LocalScope<clang::interp::ByteCodeEmitter>::addLocal(clang::interp::Scope::Local const&)
Unexecuted instantiation: clang::interp::LocalScope<clang::interp::EvalEmitter>::addLocal(clang::interp::Scope::Local const&)
398
399
0
  void emitDestructors() override {
400
0
    if (!Idx)
401
0
      return;
402
    // Emit destructor calls for local variables of record
403
    // type with a destructor.
404
0
    for (Scope::Local &Local : this->Ctx->Descriptors[*Idx]) {
405
0
      if (!Local.Desc->isPrimitive() && !Local.Desc->isPrimitiveArray()) {
406
0
        this->Ctx->emitGetPtrLocal(Local.Offset, SourceInfo{});
407
0
        this->Ctx->emitRecordDestruction(Local.Desc);
408
0
      }
409
0
    }
410
0
  }
Unexecuted instantiation: clang::interp::LocalScope<clang::interp::ByteCodeEmitter>::emitDestructors()
Unexecuted instantiation: clang::interp::LocalScope<clang::interp::EvalEmitter>::emitDestructors()
411
412
  /// Index of the scope in the chain.
413
  std::optional<unsigned> Idx;
414
};
415
416
/// Emits the destructors of the variables of \param OtherScope
417
/// when this scope is destroyed. Does not create a Scope in the bytecode at
418
/// all, this is just a RAII object to emit destructors.
419
template <class Emitter> class DestructorScope final {
420
public:
421
0
  DestructorScope(LocalScope<Emitter> &OtherScope) : OtherScope(OtherScope) {}
Unexecuted instantiation: clang::interp::DestructorScope<clang::interp::ByteCodeEmitter>::DestructorScope(clang::interp::LocalScope<clang::interp::ByteCodeEmitter>&)
Unexecuted instantiation: clang::interp::DestructorScope<clang::interp::EvalEmitter>::DestructorScope(clang::interp::LocalScope<clang::interp::EvalEmitter>&)
422
423
0
  ~DestructorScope() { OtherScope.emitDestructors(); }
Unexecuted instantiation: clang::interp::DestructorScope<clang::interp::ByteCodeEmitter>::~DestructorScope()
Unexecuted instantiation: clang::interp::DestructorScope<clang::interp::EvalEmitter>::~DestructorScope()
424
425
private:
426
  LocalScope<Emitter> &OtherScope;
427
};
428
429
/// Like a regular LocalScope, except that the destructors of all local
430
/// variables are automatically emitted when the AutoScope is destroyed.
431
template <class Emitter> class AutoScope : public LocalScope<Emitter> {
432
public:
433
  AutoScope(ByteCodeExprGen<Emitter> *Ctx)
434
0
      : LocalScope<Emitter>(Ctx), DS(*this) {}
Unexecuted instantiation: clang::interp::AutoScope<clang::interp::ByteCodeEmitter>::AutoScope(clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>*)
Unexecuted instantiation: clang::interp::AutoScope<clang::interp::EvalEmitter>::AutoScope(clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>*)
435
436
private:
437
  DestructorScope<Emitter> DS;
438
};
439
440
/// Scope for storage declared in a compound statement.
441
template <class Emitter> class BlockScope final : public AutoScope<Emitter> {
442
public:
443
0
  BlockScope(ByteCodeExprGen<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {}
Unexecuted instantiation: clang::interp::BlockScope<clang::interp::ByteCodeEmitter>::BlockScope(clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>*)
Unexecuted instantiation: clang::interp::BlockScope<clang::interp::EvalEmitter>::BlockScope(clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>*)
444
445
0
  void addExtended(const Scope::Local &Local) override {
446
    // If we to this point, just add the variable as a normal local
447
    // variable. It will be destroyed at the end of the block just
448
    // like all others.
449
0
    this->addLocal(Local);
450
0
  }
Unexecuted instantiation: clang::interp::BlockScope<clang::interp::ByteCodeEmitter>::addExtended(clang::interp::Scope::Local const&)
Unexecuted instantiation: clang::interp::BlockScope<clang::interp::EvalEmitter>::addExtended(clang::interp::Scope::Local const&)
451
};
452
453
/// Expression scope which tracks potentially lifetime extended
454
/// temporaries which are hoisted to the parent scope on exit.
455
template <class Emitter> class ExprScope final : public AutoScope<Emitter> {
456
public:
457
0
  ExprScope(ByteCodeExprGen<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {}
Unexecuted instantiation: clang::interp::ExprScope<clang::interp::ByteCodeEmitter>::ExprScope(clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>*)
Unexecuted instantiation: clang::interp::ExprScope<clang::interp::EvalEmitter>::ExprScope(clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>*)
458
459
0
  void addExtended(const Scope::Local &Local) override {
460
0
    if (this->Parent)
461
0
      this->Parent->addLocal(Local);
462
0
  }
Unexecuted instantiation: clang::interp::ExprScope<clang::interp::ByteCodeEmitter>::addExtended(clang::interp::Scope::Local const&)
Unexecuted instantiation: clang::interp::ExprScope<clang::interp::EvalEmitter>::addExtended(clang::interp::Scope::Local const&)
463
};
464
465
template <class Emitter> class ArrayIndexScope final {
466
public:
467
0
  ArrayIndexScope(ByteCodeExprGen<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {
468
0
    OldArrayIndex = Ctx->ArrayIndex;
469
0
    Ctx->ArrayIndex = Index;
470
0
  }
Unexecuted instantiation: clang::interp::ArrayIndexScope<clang::interp::ByteCodeEmitter>::ArrayIndexScope(clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>*, unsigned long)
Unexecuted instantiation: clang::interp::ArrayIndexScope<clang::interp::EvalEmitter>::ArrayIndexScope(clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>*, unsigned long)
471
472
0
  ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; }
Unexecuted instantiation: clang::interp::ArrayIndexScope<clang::interp::ByteCodeEmitter>::~ArrayIndexScope()
Unexecuted instantiation: clang::interp::ArrayIndexScope<clang::interp::EvalEmitter>::~ArrayIndexScope()
473
474
private:
475
  ByteCodeExprGen<Emitter> *Ctx;
476
  std::optional<uint64_t> OldArrayIndex;
477
};
478
479
template <class Emitter> class SourceLocScope final {
480
public:
481
  SourceLocScope(ByteCodeExprGen<Emitter> *Ctx, const Expr *DefaultExpr)
482
0
      : Ctx(Ctx) {
483
0
    assert(DefaultExpr);
484
    // We only switch if the current SourceLocDefaultExpr is null.
485
0
    if (!Ctx->SourceLocDefaultExpr) {
486
0
      Enabled = true;
487
0
      Ctx->SourceLocDefaultExpr = DefaultExpr;
488
0
    }
489
0
  }
Unexecuted instantiation: clang::interp::SourceLocScope<clang::interp::ByteCodeEmitter>::SourceLocScope(clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>*, clang::Expr const*)
Unexecuted instantiation: clang::interp::SourceLocScope<clang::interp::EvalEmitter>::SourceLocScope(clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>*, clang::Expr const*)
490
491
0
  ~SourceLocScope() {
492
0
    if (Enabled)
493
0
      Ctx->SourceLocDefaultExpr = nullptr;
494
0
  }
Unexecuted instantiation: clang::interp::SourceLocScope<clang::interp::ByteCodeEmitter>::~SourceLocScope()
Unexecuted instantiation: clang::interp::SourceLocScope<clang::interp::EvalEmitter>::~SourceLocScope()
495
496
private:
497
  ByteCodeExprGen<Emitter> *Ctx;
498
  bool Enabled = false;
499
};
500
501
} // namespace interp
502
} // namespace clang
503
504
#endif