1//===--- Compiler.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
26namespace clang {
27class QualType;
28
29namespace interp {
30
31template <class Emitter> class LocalScope;
32template <class Emitter> class DestructorScope;
33template <class Emitter> class VariableScope;
34template <class Emitter> class DeclScope;
35template <class Emitter> class InitLinkScope;
36template <class Emitter> class InitStackScope;
37template <class Emitter> class OptionScope;
38template <class Emitter> class ArrayIndexScope;
39template <class Emitter> class SourceLocScope;
40template <class Emitter> class LoopScope;
41template <class Emitter> class LabelScope;
42template <class Emitter> class SwitchScope;
43template <class Emitter> class StmtExprScope;
44
45template <class Emitter> class Compiler;
46struct InitLink {
47public:
48 enum {
49 K_This = 0,
50 K_Field = 1,
51 K_Temp = 2,
52 K_Decl = 3,
53 K_Elem = 5,
54 K_RVO = 6,
55 K_InitList = 7
56 };
57
58 static InitLink This() { return InitLink{K_This}; }
59 static InitLink InitList() { return InitLink{K_InitList}; }
60 static InitLink RVO() { return InitLink{K_RVO}; }
61 static InitLink Field(unsigned Offset) {
62 InitLink IL{K_Field};
63 IL.Offset = Offset;
64 return IL;
65 }
66 static InitLink Temp(unsigned Offset) {
67 InitLink IL{K_Temp};
68 IL.Offset = Offset;
69 return IL;
70 }
71 static InitLink Decl(const ValueDecl *D) {
72 InitLink IL{K_Decl};
73 IL.D = D;
74 return IL;
75 }
76 static InitLink Elem(unsigned Index) {
77 InitLink IL{K_Elem};
78 IL.Offset = Index;
79 return IL;
80 }
81
82 InitLink(uint8_t Kind) : Kind(Kind) {}
83 template <class Emitter>
84 bool emit(Compiler<Emitter> *Ctx, const Expr *E) const;
85
86 uint32_t Kind;
87 union {
88 unsigned Offset;
89 const ValueDecl *D;
90 };
91};
92
93/// State encapsulating if a the variable creation has been successful,
94/// unsuccessful, or no variable has been created at all.
95struct VarCreationState {
96 std::optional<bool> S = std::nullopt;
97 VarCreationState() = default;
98 VarCreationState(bool b) : S(b) {}
99 static VarCreationState NotCreated() { return VarCreationState(); }
100
101 operator bool() const { return S && *S; }
102 bool notCreated() const { return !S; }
103};
104
105enum class ScopeKind { Call, Block };
106
107/// Compilation context for expressions.
108template <class Emitter>
109class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
110 public Emitter {
111protected:
112 // Aliases for types defined in the emitter.
113 using LabelTy = typename Emitter::LabelTy;
114 using AddrTy = typename Emitter::AddrTy;
115 using OptLabelTy = std::optional<LabelTy>;
116 using CaseMap = llvm::DenseMap<const SwitchCase *, LabelTy>;
117
118 /// Current compilation context.
119 Context &Ctx;
120 /// Program to link to.
121 Program &P;
122
123public:
124 /// Initializes the compiler and the backend emitter.
125 template <typename... Tys>
126 Compiler(Context &Ctx, Program &P, Tys &&...Args)
127 : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
128
129 // Expressions.
130 bool VisitCastExpr(const CastExpr *E);
131 bool VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *E);
132 bool VisitIntegerLiteral(const IntegerLiteral *E);
133 bool VisitFloatingLiteral(const FloatingLiteral *E);
134 bool VisitImaginaryLiteral(const ImaginaryLiteral *E);
135 bool VisitFixedPointLiteral(const FixedPointLiteral *E);
136 bool VisitParenExpr(const ParenExpr *E);
137 bool VisitBinaryOperator(const BinaryOperator *E);
138 bool VisitLogicalBinOp(const BinaryOperator *E);
139 bool VisitPointerArithBinOp(const BinaryOperator *E);
140 bool VisitComplexBinOp(const BinaryOperator *E);
141 bool VisitVectorBinOp(const BinaryOperator *E);
142 bool VisitFixedPointBinOp(const BinaryOperator *E);
143 bool VisitFixedPointUnaryOperator(const UnaryOperator *E);
144 bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
145 bool VisitCallExpr(const CallExpr *E);
146 bool VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinID);
147 bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E);
148 bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);
149 bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
150 bool VisitGNUNullExpr(const GNUNullExpr *E);
151 bool VisitCXXThisExpr(const CXXThisExpr *E);
152 bool VisitUnaryOperator(const UnaryOperator *E);
153 bool VisitVectorUnaryOperator(const UnaryOperator *E);
154 bool VisitComplexUnaryOperator(const UnaryOperator *E);
155 bool VisitDeclRefExpr(const DeclRefExpr *E);
156 bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
157 bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E);
158 bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
159 bool VisitInitListExpr(const InitListExpr *E);
160 bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
161 bool VisitConstantExpr(const ConstantExpr *E);
162 bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
163 bool VisitMemberExpr(const MemberExpr *E);
164 bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E);
165 bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);
166 bool VisitOpaqueValueExpr(const OpaqueValueExpr *E);
167 bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E);
168 bool VisitStringLiteral(const StringLiteral *E);
169 bool VisitObjCStringLiteral(const ObjCStringLiteral *E);
170 bool VisitObjCEncodeExpr(const ObjCEncodeExpr *E);
171 bool VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *E);
172 bool VisitCharacterLiteral(const CharacterLiteral *E);
173 bool VisitCompoundAssignOperator(const CompoundAssignOperator *E);
174 bool VisitFloatCompoundAssignOperator(const CompoundAssignOperator *E);
175 bool VisitPointerCompoundAssignOperator(const CompoundAssignOperator *E);
176 bool VisitExprWithCleanups(const ExprWithCleanups *E);
177 bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
178 bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E);
179 bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
180 bool VisitTypeTraitExpr(const TypeTraitExpr *E);
181 bool VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E);
182 bool VisitLambdaExpr(const LambdaExpr *E);
183 bool VisitPredefinedExpr(const PredefinedExpr *E);
184 bool VisitCXXThrowExpr(const CXXThrowExpr *E);
185 bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E);
186 bool VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E);
187 bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);
188 bool VisitCXXConstructExpr(const CXXConstructExpr *E);
189 bool VisitSourceLocExpr(const SourceLocExpr *E);
190 bool VisitOffsetOfExpr(const OffsetOfExpr *E);
191 bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E);
192 bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
193 bool VisitGenericSelectionExpr(const GenericSelectionExpr *E);
194 bool VisitChooseExpr(const ChooseExpr *E);
195 bool VisitEmbedExpr(const EmbedExpr *E);
196 bool VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E);
197 bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
198 bool VisitExpressionTraitExpr(const ExpressionTraitExpr *E);
199 bool VisitCXXUuidofExpr(const CXXUuidofExpr *E);
200 bool VisitRequiresExpr(const RequiresExpr *E);
201 bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);
202 bool VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *E);
203 bool VisitPseudoObjectExpr(const PseudoObjectExpr *E);
204 bool VisitPackIndexingExpr(const PackIndexingExpr *E);
205 bool VisitRecoveryExpr(const RecoveryExpr *E);
206 bool VisitAddrLabelExpr(const AddrLabelExpr *E);
207 bool VisitConvertVectorExpr(const ConvertVectorExpr *E);
208 bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);
209 bool VisitExtVectorElementExpr(const ExtVectorElementExpr *E);
210 bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E);
211 bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
212 bool VisitStmtExpr(const StmtExpr *E);
213 bool VisitCXXNewExpr(const CXXNewExpr *E);
214 bool VisitCXXDeleteExpr(const CXXDeleteExpr *E);
215 bool VisitBlockExpr(const BlockExpr *E);
216 bool VisitCXXTypeidExpr(const CXXTypeidExpr *E);
217
218 // Statements.
219 bool visitCompoundStmt(const CompoundStmt *S);
220 bool visitDeclStmt(const DeclStmt *DS, bool EvaluateConditionDecl = false);
221 bool visitReturnStmt(const ReturnStmt *RS);
222 bool visitIfStmt(const IfStmt *IS);
223 bool visitWhileStmt(const WhileStmt *S);
224 bool visitDoStmt(const DoStmt *S);
225 bool visitForStmt(const ForStmt *S);
226 bool visitCXXForRangeStmt(const CXXForRangeStmt *S);
227 bool visitBreakStmt(const BreakStmt *S);
228 bool visitContinueStmt(const ContinueStmt *S);
229 bool visitSwitchStmt(const SwitchStmt *S);
230 bool visitCaseStmt(const CaseStmt *S);
231 bool visitDefaultStmt(const DefaultStmt *S);
232 bool visitAttributedStmt(const AttributedStmt *S);
233 bool visitCXXTryStmt(const CXXTryStmt *S);
234
235protected:
236 bool visitStmt(const Stmt *S);
237 bool visitExpr(const Expr *E, bool DestroyToplevelScope) override;
238 bool visitFunc(const FunctionDecl *F) override;
239
240 bool visitDeclAndReturn(const VarDecl *VD, bool ConstantContext) override;
241
242protected:
243 /// Emits scope cleanup instructions.
244 void emitCleanup();
245
246 /// Returns a record type from a record or pointer type.
247 const RecordType *getRecordTy(QualType Ty);
248
249 /// Returns a record from a record or pointer type.
250 Record *getRecord(QualType Ty);
251 Record *getRecord(const RecordDecl *RD);
252
253 /// Returns a function for the given FunctionDecl.
254 /// If the function does not exist yet, it is compiled.
255 const Function *getFunction(const FunctionDecl *FD);
256
257 std::optional<PrimType> classify(const Expr *E) const {
258 return Ctx.classify(E);
259 }
260 std::optional<PrimType> classify(QualType Ty) const {
261 return Ctx.classify(T: Ty);
262 }
263
264 /// Classifies a known primitive type.
265 PrimType classifyPrim(QualType Ty) const {
266 if (auto T = classify(Ty)) {
267 return *T;
268 }
269 llvm_unreachable("not a primitive type");
270 }
271 /// Classifies a known primitive expression.
272 PrimType classifyPrim(const Expr *E) const {
273 if (auto T = classify(E))
274 return *T;
275 llvm_unreachable("not a primitive type");
276 }
277
278 /// Evaluates an expression and places the result on the stack. If the
279 /// expression is of composite type, a local variable will be created
280 /// and a pointer to said variable will be placed on the stack.
281 bool visit(const Expr *E) override;
282 /// Compiles an initializer. This is like visit() but it will never
283 /// create a variable and instead rely on a variable already having
284 /// been created. visitInitializer() then relies on a pointer to this
285 /// variable being on top of the stack.
286 bool visitInitializer(const Expr *E);
287 /// Evaluates an expression for side effects and discards the result.
288 bool discard(const Expr *E);
289 /// Just pass evaluation on to \p E. This leaves all the parsing flags
290 /// intact.
291 bool delegate(const Expr *E);
292 /// Creates and initializes a variable from the given decl.
293 VarCreationState visitVarDecl(const VarDecl *VD, bool Toplevel = false,
294 bool IsConstexprUnknown = false);
295 VarCreationState visitDecl(const VarDecl *VD,
296 bool IsConstexprUnknown = false);
297 /// Visit an APValue.
298 bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E);
299 bool visitAPValueInitializer(const APValue &Val, const Expr *E, QualType T);
300 /// Visit the given decl as if we have a reference to it.
301 bool visitDeclRef(const ValueDecl *D, const Expr *E);
302
303 /// Visits an expression and converts it to a boolean.
304 bool visitBool(const Expr *E);
305
306 bool visitInitList(ArrayRef<const Expr *> Inits, const Expr *ArrayFiller,
307 const Expr *E);
308 bool visitArrayElemInit(unsigned ElemIndex, const Expr *Init,
309 std::optional<PrimType> InitT);
310 bool visitCallArgs(ArrayRef<const Expr *> Args, const FunctionDecl *FuncDecl);
311
312 /// Creates a local primitive value.
313 unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst,
314 const ValueDecl *ExtendingDecl = nullptr,
315 ScopeKind SC = ScopeKind::Block,
316 bool IsConstexprUnknown = false);
317
318 /// Allocates a space storing a local given its type.
319 std::optional<unsigned>
320 allocateLocal(DeclTy &&Decl, QualType Ty = QualType(),
321 const ValueDecl *ExtendingDecl = nullptr,
322 ScopeKind = ScopeKind::Block, bool IsConstexprUnknown = false);
323 std::optional<unsigned> allocateTemporary(const Expr *E);
324
325private:
326 friend class VariableScope<Emitter>;
327 friend class LocalScope<Emitter>;
328 friend class DestructorScope<Emitter>;
329 friend class DeclScope<Emitter>;
330 friend class InitLinkScope<Emitter>;
331 friend class InitStackScope<Emitter>;
332 friend class OptionScope<Emitter>;
333 friend class ArrayIndexScope<Emitter>;
334 friend class SourceLocScope<Emitter>;
335 friend struct InitLink;
336 friend class LoopScope<Emitter>;
337 friend class LabelScope<Emitter>;
338 friend class SwitchScope<Emitter>;
339 friend class StmtExprScope<Emitter>;
340
341 /// Emits a zero initializer.
342 bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E);
343 bool visitZeroRecordInitializer(const Record *R, const Expr *E);
344 bool visitZeroArrayInitializer(QualType T, const Expr *E);
345
346 /// Emits an APSInt constant.
347 bool emitConst(const llvm::APSInt &Value, PrimType Ty, const Expr *E);
348 bool emitConst(const llvm::APSInt &Value, const Expr *E);
349 bool emitConst(const llvm::APInt &Value, const Expr *E) {
350 return emitConst(static_cast<llvm::APSInt>(Value), E);
351 }
352
353 /// Emits an integer constant.
354 template <typename T> bool emitConst(T Value, PrimType Ty, const Expr *E);
355 template <typename T> bool emitConst(T Value, const Expr *E);
356 bool emitBool(bool V, const Expr *E) override {
357 return this->emitConst(V, E);
358 }
359
360 llvm::RoundingMode getRoundingMode(const Expr *E) const {
361 FPOptions FPO = E->getFPFeaturesInEffect(LO: Ctx.getLangOpts());
362
363 if (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic)
364 return llvm::RoundingMode::NearestTiesToEven;
365
366 return FPO.getRoundingMode();
367 }
368
369 uint32_t getFPOptions(const Expr *E) const {
370 return E->getFPFeaturesInEffect(LO: Ctx.getLangOpts()).getAsOpaqueInt();
371 }
372
373 bool emitPrimCast(PrimType FromT, PrimType ToT, QualType ToQT, const Expr *E);
374 PrimType classifyComplexElementType(QualType T) const {
375 assert(T->isAnyComplexType());
376
377 QualType ElemType = T->getAs<ComplexType>()->getElementType();
378
379 return *this->classify(ElemType);
380 }
381
382 PrimType classifyVectorElementType(QualType T) const {
383 assert(T->isVectorType());
384 return *this->classify(T->getAs<VectorType>()->getElementType());
385 }
386
387 bool emitComplexReal(const Expr *SubExpr);
388 bool emitComplexBoolCast(const Expr *E);
389 bool emitComplexComparison(const Expr *LHS, const Expr *RHS,
390 const BinaryOperator *E);
391 bool emitRecordDestruction(const Record *R, SourceInfo Loc);
392 bool emitDestruction(const Descriptor *Desc, SourceInfo Loc);
393 bool emitDummyPtr(const DeclTy &D, const Expr *E);
394 bool emitFloat(const APFloat &F, const Expr *E);
395 unsigned collectBaseOffset(const QualType BaseType,
396 const QualType DerivedType);
397 bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD);
398 bool emitBuiltinBitCast(const CastExpr *E);
399 bool compileConstructor(const CXXConstructorDecl *Ctor);
400 bool compileDestructor(const CXXDestructorDecl *Dtor);
401 bool compileUnionAssignmentOperator(const CXXMethodDecl *MD);
402
403 bool checkLiteralType(const Expr *E);
404 bool maybeEmitDeferredVarInit(const VarDecl *VD);
405
406protected:
407 /// Variable to storage mapping.
408 llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
409
410 /// OpaqueValueExpr to location mapping.
411 llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs;
412
413 /// Current scope.
414 VariableScope<Emitter> *VarScope = nullptr;
415
416 /// Current argument index. Needed to emit ArrayInitIndexExpr.
417 std::optional<uint64_t> ArrayIndex;
418
419 /// DefaultInit- or DefaultArgExpr, needed for SourceLocExpr.
420 const Expr *SourceLocDefaultExpr = nullptr;
421
422 /// Flag indicating if return value is to be discarded.
423 bool DiscardResult = false;
424
425 bool InStmtExpr = false;
426
427 /// Flag inidicating if we're initializing an already created
428 /// variable. This is set in visitInitializer().
429 bool Initializing = false;
430 const ValueDecl *InitializingDecl = nullptr;
431
432 llvm::SmallVector<InitLink> InitStack;
433 bool InitStackActive = false;
434
435 /// Type of the expression returned by the function.
436 std::optional<PrimType> ReturnType;
437
438 /// Switch case mapping.
439 CaseMap CaseLabels;
440
441 /// Scope to cleanup until when we see a break statement.
442 VariableScope<Emitter> *BreakVarScope = nullptr;
443 /// Point to break to.
444 OptLabelTy BreakLabel;
445 /// Scope to cleanup until when we see a continue statement.
446 VariableScope<Emitter> *ContinueVarScope = nullptr;
447 /// Point to continue to.
448 OptLabelTy ContinueLabel;
449 /// Default case label.
450 OptLabelTy DefaultLabel;
451
452 const FunctionDecl *CompilingFunction = nullptr;
453};
454
455extern template class Compiler<ByteCodeEmitter>;
456extern template class Compiler<EvalEmitter>;
457
458/// Scope chain managing the variable lifetimes.
459template <class Emitter> class VariableScope {
460public:
461 VariableScope(Compiler<Emitter> *Ctx, const ValueDecl *VD,
462 ScopeKind Kind = ScopeKind::Block)
463 : Ctx(Ctx), Parent(Ctx->VarScope), ValDecl(VD), Kind(Kind) {
464 Ctx->VarScope = this;
465 }
466
467 virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
468
469 virtual void addLocal(const Scope::Local &Local) {
470 llvm_unreachable("Shouldn't be called");
471 }
472
473 void addExtended(const Scope::Local &Local, const ValueDecl *ExtendingDecl) {
474 // Walk up the chain of scopes until we find the one for ExtendingDecl.
475 // If there is no such scope, attach it to the parent one.
476 VariableScope *P = this;
477 while (P) {
478 if (P->ValDecl == ExtendingDecl) {
479 P->addLocal(Local);
480 return;
481 }
482 P = P->Parent;
483 if (!P)
484 break;
485 }
486
487 // Use the parent scope.
488 if (this->Parent)
489 this->Parent->addLocal(Local);
490 else
491 this->addLocal(Local);
492 }
493
494 /// Like addExtended, but adds to the nearest scope of the given kind.
495 void addForScopeKind(const Scope::Local &Local, ScopeKind Kind) {
496 VariableScope *P = this;
497 while (P) {
498 if (P->Kind == Kind) {
499 P->addLocal(Local);
500 return;
501 }
502 P = P->Parent;
503 if (!P)
504 break;
505 }
506
507 // Add to this scope.
508 this->addLocal(Local);
509 }
510
511 virtual void emitDestruction() {}
512 virtual bool emitDestructors(const Expr *E = nullptr) { return true; }
513 virtual bool destroyLocals(const Expr *E = nullptr) { return true; }
514 VariableScope *getParent() const { return Parent; }
515 ScopeKind getKind() const { return Kind; }
516
517protected:
518 /// Compiler instance.
519 Compiler<Emitter> *Ctx;
520 /// Link to the parent scope.
521 VariableScope *Parent;
522 const ValueDecl *ValDecl = nullptr;
523 ScopeKind Kind;
524};
525
526/// Generic scope for local variables.
527template <class Emitter> class LocalScope : public VariableScope<Emitter> {
528public:
529 LocalScope(Compiler<Emitter> *Ctx, ScopeKind Kind = ScopeKind::Block)
530 : VariableScope<Emitter>(Ctx, nullptr, Kind) {}
531 LocalScope(Compiler<Emitter> *Ctx, const ValueDecl *VD)
532 : VariableScope<Emitter>(Ctx, VD) {}
533
534 /// Emit a Destroy op for this scope.
535 ~LocalScope() override {
536 if (!Idx)
537 return;
538 this->Ctx->emitDestroy(*Idx, SourceInfo{});
539 removeStoredOpaqueValues();
540 }
541
542 /// Overriden to support explicit destruction.
543 void emitDestruction() override {
544 if (!Idx)
545 return;
546
547 this->emitDestructors();
548 this->Ctx->emitDestroy(*Idx, SourceInfo{});
549 }
550
551 /// Explicit destruction of local variables.
552 bool destroyLocals(const Expr *E = nullptr) override {
553 if (!Idx)
554 return true;
555
556 // NB: We are *not* resetting Idx here as to allow multiple
557 // calls to destroyLocals().
558 bool Success = this->emitDestructors(E);
559 this->Ctx->emitDestroy(*Idx, E);
560 return Success;
561 }
562
563 void addLocal(const Scope::Local &Local) override {
564 if (!Idx) {
565 Idx = this->Ctx->Descriptors.size();
566 this->Ctx->Descriptors.emplace_back();
567 this->Ctx->emitInitScope(*Idx, {});
568 }
569
570 this->Ctx->Descriptors[*Idx].emplace_back(Local);
571 }
572
573 bool emitDestructors(const Expr *E = nullptr) override {
574 if (!Idx)
575 return true;
576 // Emit destructor calls for local variables of record
577 // type with a destructor.
578 for (Scope::Local &Local : llvm::reverse(this->Ctx->Descriptors[*Idx])) {
579 if (Local.Desc->hasTrivialDtor())
580 continue;
581 if (!this->Ctx->emitGetPtrLocal(Local.Offset, E))
582 return false;
583
584 if (!this->Ctx->emitDestruction(Local.Desc, Local.Desc->getLoc()))
585 return false;
586
587 if (!this->Ctx->emitPopPtr(E))
588 return false;
589 removeIfStoredOpaqueValue(Local);
590 }
591 return true;
592 }
593
594 void removeStoredOpaqueValues() {
595 if (!Idx)
596 return;
597
598 for (const Scope::Local &Local : this->Ctx->Descriptors[*Idx]) {
599 removeIfStoredOpaqueValue(Local);
600 }
601 }
602
603 void removeIfStoredOpaqueValue(const Scope::Local &Local) {
604 if (const auto *OVE =
605 llvm::dyn_cast_if_present<OpaqueValueExpr>(Val: Local.Desc->asExpr())) {
606 if (auto It = this->Ctx->OpaqueExprs.find(OVE);
607 It != this->Ctx->OpaqueExprs.end())
608 this->Ctx->OpaqueExprs.erase(It);
609 };
610 }
611
612 /// Index of the scope in the chain.
613 std::optional<unsigned> Idx;
614};
615
616/// Scope for storage declared in a compound statement.
617// FIXME: Remove?
618template <class Emitter> class BlockScope final : public LocalScope<Emitter> {
619public:
620 BlockScope(Compiler<Emitter> *Ctx, ScopeKind Kind = ScopeKind::Block)
621 : LocalScope<Emitter>(Ctx, Kind) {}
622};
623
624template <class Emitter> class ArrayIndexScope final {
625public:
626 ArrayIndexScope(Compiler<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {
627 OldArrayIndex = Ctx->ArrayIndex;
628 Ctx->ArrayIndex = Index;
629 }
630
631 ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; }
632
633private:
634 Compiler<Emitter> *Ctx;
635 std::optional<uint64_t> OldArrayIndex;
636};
637
638template <class Emitter> class SourceLocScope final {
639public:
640 SourceLocScope(Compiler<Emitter> *Ctx, const Expr *DefaultExpr) : Ctx(Ctx) {
641 assert(DefaultExpr);
642 // We only switch if the current SourceLocDefaultExpr is null.
643 if (!Ctx->SourceLocDefaultExpr) {
644 Enabled = true;
645 Ctx->SourceLocDefaultExpr = DefaultExpr;
646 }
647 }
648
649 ~SourceLocScope() {
650 if (Enabled)
651 Ctx->SourceLocDefaultExpr = nullptr;
652 }
653
654private:
655 Compiler<Emitter> *Ctx;
656 bool Enabled = false;
657};
658
659template <class Emitter> class InitLinkScope final {
660public:
661 InitLinkScope(Compiler<Emitter> *Ctx, InitLink &&Link) : Ctx(Ctx) {
662 Ctx->InitStack.push_back(std::move(Link));
663 }
664
665 ~InitLinkScope() { this->Ctx->InitStack.pop_back(); }
666
667private:
668 Compiler<Emitter> *Ctx;
669};
670
671template <class Emitter> class InitStackScope final {
672public:
673 InitStackScope(Compiler<Emitter> *Ctx, bool Active)
674 : Ctx(Ctx), OldValue(Ctx->InitStackActive) {
675 Ctx->InitStackActive = Active;
676 }
677
678 ~InitStackScope() { this->Ctx->InitStackActive = OldValue; }
679
680private:
681 Compiler<Emitter> *Ctx;
682 bool OldValue;
683};
684
685} // namespace interp
686} // namespace clang
687
688#endif
689

source code of clang/lib/AST/ByteCode/Compiler.h