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