Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/Compiler.h
213799 views
//===--- Compiler.h - Code generator for expressions -----*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Defines the constexpr bytecode compiler.9//10//===----------------------------------------------------------------------===//1112#ifndef LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H13#define LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H1415#include "ByteCodeEmitter.h"16#include "EvalEmitter.h"17#include "Pointer.h"18#include "PrimType.h"19#include "Record.h"20#include "clang/AST/Decl.h"21#include "clang/AST/Expr.h"22#include "clang/AST/StmtVisitor.h"23#include "clang/Basic/TargetInfo.h"2425namespace clang {26class QualType;2728namespace interp {2930template <class Emitter> class LocalScope;31template <class Emitter> class DestructorScope;32template <class Emitter> class VariableScope;33template <class Emitter> class DeclScope;34template <class Emitter> class InitLinkScope;35template <class Emitter> class InitStackScope;36template <class Emitter> class OptionScope;37template <class Emitter> class ArrayIndexScope;38template <class Emitter> class SourceLocScope;39template <class Emitter> class LoopScope;40template <class Emitter> class LabelScope;41template <class Emitter> class SwitchScope;42template <class Emitter> class StmtExprScope;4344template <class Emitter> class Compiler;45struct InitLink {46public:47enum {48K_This = 0,49K_Field = 1,50K_Temp = 2,51K_Decl = 3,52K_Elem = 5,53K_RVO = 6,54K_InitList = 755};5657static InitLink This() { return InitLink{K_This}; }58static InitLink InitList() { return InitLink{K_InitList}; }59static InitLink RVO() { return InitLink{K_RVO}; }60static InitLink Field(unsigned Offset) {61InitLink IL{K_Field};62IL.Offset = Offset;63return IL;64}65static InitLink Temp(unsigned Offset) {66InitLink IL{K_Temp};67IL.Offset = Offset;68return IL;69}70static InitLink Decl(const ValueDecl *D) {71InitLink IL{K_Decl};72IL.D = D;73return IL;74}75static InitLink Elem(unsigned Index) {76InitLink IL{K_Elem};77IL.Offset = Index;78return IL;79}8081InitLink(uint8_t Kind) : Kind(Kind) {}82template <class Emitter>83bool emit(Compiler<Emitter> *Ctx, const Expr *E) const;8485uint32_t Kind;86union {87unsigned Offset;88const ValueDecl *D;89};90};9192/// State encapsulating if a the variable creation has been successful,93/// unsuccessful, or no variable has been created at all.94struct VarCreationState {95std::optional<bool> S = std::nullopt;96VarCreationState() = default;97VarCreationState(bool b) : S(b) {}98static VarCreationState NotCreated() { return VarCreationState(); }99100operator bool() const { return S && *S; }101bool notCreated() const { return !S; }102};103104enum class ScopeKind { Call, Block };105106/// Compilation context for expressions.107template <class Emitter>108class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,109public Emitter {110protected:111// Aliases for types defined in the emitter.112using LabelTy = typename Emitter::LabelTy;113using AddrTy = typename Emitter::AddrTy;114using OptLabelTy = std::optional<LabelTy>;115using CaseMap = llvm::DenseMap<const SwitchCase *, LabelTy>;116117/// Current compilation context.118Context &Ctx;119/// Program to link to.120Program &P;121122public:123/// Initializes the compiler and the backend emitter.124template <typename... Tys>125Compiler(Context &Ctx, Program &P, Tys &&...Args)126: Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}127128// Expressions.129bool VisitCastExpr(const CastExpr *E);130bool VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *E);131bool VisitIntegerLiteral(const IntegerLiteral *E);132bool VisitFloatingLiteral(const FloatingLiteral *E);133bool VisitImaginaryLiteral(const ImaginaryLiteral *E);134bool VisitFixedPointLiteral(const FixedPointLiteral *E);135bool VisitParenExpr(const ParenExpr *E);136bool VisitBinaryOperator(const BinaryOperator *E);137bool VisitLogicalBinOp(const BinaryOperator *E);138bool VisitPointerArithBinOp(const BinaryOperator *E);139bool VisitComplexBinOp(const BinaryOperator *E);140bool VisitVectorBinOp(const BinaryOperator *E);141bool VisitFixedPointBinOp(const BinaryOperator *E);142bool VisitFixedPointUnaryOperator(const UnaryOperator *E);143bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);144bool VisitCallExpr(const CallExpr *E);145bool VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinID);146bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E);147bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);148bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);149bool VisitGNUNullExpr(const GNUNullExpr *E);150bool VisitCXXThisExpr(const CXXThisExpr *E);151bool VisitUnaryOperator(const UnaryOperator *E);152bool VisitVectorUnaryOperator(const UnaryOperator *E);153bool VisitComplexUnaryOperator(const UnaryOperator *E);154bool VisitDeclRefExpr(const DeclRefExpr *E);155bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);156bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E);157bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);158bool VisitInitListExpr(const InitListExpr *E);159bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);160bool VisitConstantExpr(const ConstantExpr *E);161bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);162bool VisitMemberExpr(const MemberExpr *E);163bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E);164bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);165bool VisitOpaqueValueExpr(const OpaqueValueExpr *E);166bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E);167bool VisitStringLiteral(const StringLiteral *E);168bool VisitObjCStringLiteral(const ObjCStringLiteral *E);169bool VisitObjCEncodeExpr(const ObjCEncodeExpr *E);170bool VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *E);171bool VisitCharacterLiteral(const CharacterLiteral *E);172bool VisitCompoundAssignOperator(const CompoundAssignOperator *E);173bool VisitFloatCompoundAssignOperator(const CompoundAssignOperator *E);174bool VisitPointerCompoundAssignOperator(const CompoundAssignOperator *E);175bool VisitExprWithCleanups(const ExprWithCleanups *E);176bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);177bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E);178bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);179bool VisitTypeTraitExpr(const TypeTraitExpr *E);180bool VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E);181bool VisitLambdaExpr(const LambdaExpr *E);182bool VisitPredefinedExpr(const PredefinedExpr *E);183bool VisitCXXThrowExpr(const CXXThrowExpr *E);184bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E);185bool VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E);186bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);187bool VisitCXXConstructExpr(const CXXConstructExpr *E);188bool VisitSourceLocExpr(const SourceLocExpr *E);189bool VisitOffsetOfExpr(const OffsetOfExpr *E);190bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E);191bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);192bool VisitGenericSelectionExpr(const GenericSelectionExpr *E);193bool VisitChooseExpr(const ChooseExpr *E);194bool VisitEmbedExpr(const EmbedExpr *E);195bool VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E);196bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);197bool VisitExpressionTraitExpr(const ExpressionTraitExpr *E);198bool VisitCXXUuidofExpr(const CXXUuidofExpr *E);199bool VisitRequiresExpr(const RequiresExpr *E);200bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);201bool VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *E);202bool VisitPseudoObjectExpr(const PseudoObjectExpr *E);203bool VisitPackIndexingExpr(const PackIndexingExpr *E);204bool VisitRecoveryExpr(const RecoveryExpr *E);205bool VisitAddrLabelExpr(const AddrLabelExpr *E);206bool VisitConvertVectorExpr(const ConvertVectorExpr *E);207bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);208bool VisitExtVectorElementExpr(const ExtVectorElementExpr *E);209bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E);210bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);211bool VisitStmtExpr(const StmtExpr *E);212bool VisitCXXNewExpr(const CXXNewExpr *E);213bool VisitCXXDeleteExpr(const CXXDeleteExpr *E);214bool VisitBlockExpr(const BlockExpr *E);215bool VisitCXXTypeidExpr(const CXXTypeidExpr *E);216217// Statements.218bool visitCompoundStmt(const CompoundStmt *S);219bool visitDeclStmt(const DeclStmt *DS, bool EvaluateConditionDecl = false);220bool visitReturnStmt(const ReturnStmt *RS);221bool visitIfStmt(const IfStmt *IS);222bool visitWhileStmt(const WhileStmt *S);223bool visitDoStmt(const DoStmt *S);224bool visitForStmt(const ForStmt *S);225bool visitCXXForRangeStmt(const CXXForRangeStmt *S);226bool visitBreakStmt(const BreakStmt *S);227bool visitContinueStmt(const ContinueStmt *S);228bool visitSwitchStmt(const SwitchStmt *S);229bool visitCaseStmt(const CaseStmt *S);230bool visitDefaultStmt(const DefaultStmt *S);231bool visitAttributedStmt(const AttributedStmt *S);232bool visitCXXTryStmt(const CXXTryStmt *S);233234protected:235bool visitStmt(const Stmt *S);236bool visitExpr(const Expr *E, bool DestroyToplevelScope) override;237bool visitFunc(const FunctionDecl *F) override;238239bool visitDeclAndReturn(const VarDecl *VD, bool ConstantContext) override;240241protected:242/// Emits scope cleanup instructions.243void emitCleanup();244245/// Returns a record type from a record or pointer type.246const RecordType *getRecordTy(QualType Ty);247248/// Returns a record from a record or pointer type.249Record *getRecord(QualType Ty);250Record *getRecord(const RecordDecl *RD);251252/// Returns a function for the given FunctionDecl.253/// If the function does not exist yet, it is compiled.254const Function *getFunction(const FunctionDecl *FD);255256std::optional<PrimType> classify(const Expr *E) const {257return Ctx.classify(E);258}259std::optional<PrimType> classify(QualType Ty) const {260return Ctx.classify(Ty);261}262263/// Classifies a known primitive type.264PrimType classifyPrim(QualType Ty) const {265if (auto T = classify(Ty)) {266return *T;267}268llvm_unreachable("not a primitive type");269}270/// Classifies a known primitive expression.271PrimType classifyPrim(const Expr *E) const {272if (auto T = classify(E))273return *T;274llvm_unreachable("not a primitive type");275}276277/// Evaluates an expression and places the result on the stack. If the278/// expression is of composite type, a local variable will be created279/// and a pointer to said variable will be placed on the stack.280bool visit(const Expr *E) override;281/// Compiles an initializer. This is like visit() but it will never282/// create a variable and instead rely on a variable already having283/// been created. visitInitializer() then relies on a pointer to this284/// variable being on top of the stack.285bool visitInitializer(const Expr *E);286/// Evaluates an expression for side effects and discards the result.287bool discard(const Expr *E);288/// Just pass evaluation on to \p E. This leaves all the parsing flags289/// intact.290bool delegate(const Expr *E);291/// Creates and initializes a variable from the given decl.292VarCreationState visitVarDecl(const VarDecl *VD, bool Toplevel = false,293bool IsConstexprUnknown = false);294VarCreationState visitDecl(const VarDecl *VD,295bool IsConstexprUnknown = false);296/// Visit an APValue.297bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E);298bool visitAPValueInitializer(const APValue &Val, const Expr *E, QualType T);299/// Visit the given decl as if we have a reference to it.300bool visitDeclRef(const ValueDecl *D, const Expr *E);301302/// Visits an expression and converts it to a boolean.303bool visitBool(const Expr *E);304305bool visitInitList(ArrayRef<const Expr *> Inits, const Expr *ArrayFiller,306const Expr *E);307bool visitArrayElemInit(unsigned ElemIndex, const Expr *Init,308std::optional<PrimType> InitT);309bool visitCallArgs(ArrayRef<const Expr *> Args, const FunctionDecl *FuncDecl);310311/// Creates a local primitive value.312unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst,313const ValueDecl *ExtendingDecl = nullptr,314ScopeKind SC = ScopeKind::Block,315bool IsConstexprUnknown = false);316317/// Allocates a space storing a local given its type.318std::optional<unsigned>319allocateLocal(DeclTy &&Decl, QualType Ty = QualType(),320const ValueDecl *ExtendingDecl = nullptr,321ScopeKind = ScopeKind::Block, bool IsConstexprUnknown = false);322std::optional<unsigned> allocateTemporary(const Expr *E);323324private:325friend class VariableScope<Emitter>;326friend class LocalScope<Emitter>;327friend class DestructorScope<Emitter>;328friend class DeclScope<Emitter>;329friend class InitLinkScope<Emitter>;330friend class InitStackScope<Emitter>;331friend class OptionScope<Emitter>;332friend class ArrayIndexScope<Emitter>;333friend class SourceLocScope<Emitter>;334friend struct InitLink;335friend class LoopScope<Emitter>;336friend class LabelScope<Emitter>;337friend class SwitchScope<Emitter>;338friend class StmtExprScope<Emitter>;339340/// Emits a zero initializer.341bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E);342bool visitZeroRecordInitializer(const Record *R, const Expr *E);343bool visitZeroArrayInitializer(QualType T, const Expr *E);344345/// Emits an APSInt constant.346bool emitConst(const llvm::APSInt &Value, PrimType Ty, const Expr *E);347bool emitConst(const llvm::APSInt &Value, const Expr *E);348bool emitConst(const llvm::APInt &Value, const Expr *E) {349return emitConst(static_cast<llvm::APSInt>(Value), E);350}351352/// Emits an integer constant.353template <typename T> bool emitConst(T Value, PrimType Ty, const Expr *E);354template <typename T> bool emitConst(T Value, const Expr *E);355bool emitBool(bool V, const Expr *E) override {356return this->emitConst(V, E);357}358359llvm::RoundingMode getRoundingMode(const Expr *E) const {360FPOptions FPO = E->getFPFeaturesInEffect(Ctx.getLangOpts());361362if (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic)363return llvm::RoundingMode::NearestTiesToEven;364365return FPO.getRoundingMode();366}367368uint32_t getFPOptions(const Expr *E) const {369return E->getFPFeaturesInEffect(Ctx.getLangOpts()).getAsOpaqueInt();370}371372bool emitPrimCast(PrimType FromT, PrimType ToT, QualType ToQT, const Expr *E);373PrimType classifyComplexElementType(QualType T) const {374assert(T->isAnyComplexType());375376QualType ElemType = T->getAs<ComplexType>()->getElementType();377378return *this->classify(ElemType);379}380381PrimType classifyVectorElementType(QualType T) const {382assert(T->isVectorType());383return *this->classify(T->getAs<VectorType>()->getElementType());384}385386bool emitComplexReal(const Expr *SubExpr);387bool emitComplexBoolCast(const Expr *E);388bool emitComplexComparison(const Expr *LHS, const Expr *RHS,389const BinaryOperator *E);390bool emitRecordDestruction(const Record *R, SourceInfo Loc);391bool emitDestruction(const Descriptor *Desc, SourceInfo Loc);392bool emitDummyPtr(const DeclTy &D, const Expr *E);393bool emitFloat(const APFloat &F, const Expr *E);394unsigned collectBaseOffset(const QualType BaseType,395const QualType DerivedType);396bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD);397bool emitBuiltinBitCast(const CastExpr *E);398bool compileConstructor(const CXXConstructorDecl *Ctor);399bool compileDestructor(const CXXDestructorDecl *Dtor);400bool compileUnionAssignmentOperator(const CXXMethodDecl *MD);401402bool checkLiteralType(const Expr *E);403bool maybeEmitDeferredVarInit(const VarDecl *VD);404405protected:406/// Variable to storage mapping.407llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;408409/// OpaqueValueExpr to location mapping.410llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs;411412/// Current scope.413VariableScope<Emitter> *VarScope = nullptr;414415/// Current argument index. Needed to emit ArrayInitIndexExpr.416std::optional<uint64_t> ArrayIndex;417418/// DefaultInit- or DefaultArgExpr, needed for SourceLocExpr.419const Expr *SourceLocDefaultExpr = nullptr;420421/// Flag indicating if return value is to be discarded.422bool DiscardResult = false;423424bool InStmtExpr = false;425426/// Flag inidicating if we're initializing an already created427/// variable. This is set in visitInitializer().428bool Initializing = false;429const ValueDecl *InitializingDecl = nullptr;430431llvm::SmallVector<InitLink> InitStack;432bool InitStackActive = false;433434/// Type of the expression returned by the function.435std::optional<PrimType> ReturnType;436437/// Switch case mapping.438CaseMap CaseLabels;439440/// Scope to cleanup until when we see a break statement.441VariableScope<Emitter> *BreakVarScope = nullptr;442/// Point to break to.443OptLabelTy BreakLabel;444/// Scope to cleanup until when we see a continue statement.445VariableScope<Emitter> *ContinueVarScope = nullptr;446/// Point to continue to.447OptLabelTy ContinueLabel;448/// Default case label.449OptLabelTy DefaultLabel;450451const FunctionDecl *CompilingFunction = nullptr;452};453454extern template class Compiler<ByteCodeEmitter>;455extern template class Compiler<EvalEmitter>;456457/// Scope chain managing the variable lifetimes.458template <class Emitter> class VariableScope {459public:460VariableScope(Compiler<Emitter> *Ctx, const ValueDecl *VD,461ScopeKind Kind = ScopeKind::Block)462: Ctx(Ctx), Parent(Ctx->VarScope), ValDecl(VD), Kind(Kind) {463Ctx->VarScope = this;464}465466virtual ~VariableScope() { Ctx->VarScope = this->Parent; }467468virtual void addLocal(const Scope::Local &Local) {469llvm_unreachable("Shouldn't be called");470}471472void addExtended(const Scope::Local &Local, const ValueDecl *ExtendingDecl) {473// Walk up the chain of scopes until we find the one for ExtendingDecl.474// If there is no such scope, attach it to the parent one.475VariableScope *P = this;476while (P) {477if (P->ValDecl == ExtendingDecl) {478P->addLocal(Local);479return;480}481P = P->Parent;482if (!P)483break;484}485486// Use the parent scope.487if (this->Parent)488this->Parent->addLocal(Local);489else490this->addLocal(Local);491}492493/// Like addExtended, but adds to the nearest scope of the given kind.494void addForScopeKind(const Scope::Local &Local, ScopeKind Kind) {495VariableScope *P = this;496while (P) {497if (P->Kind == Kind) {498P->addLocal(Local);499return;500}501P = P->Parent;502if (!P)503break;504}505506// Add to this scope.507this->addLocal(Local);508}509510virtual void emitDestruction() {}511virtual bool emitDestructors(const Expr *E = nullptr) { return true; }512virtual bool destroyLocals(const Expr *E = nullptr) { return true; }513VariableScope *getParent() const { return Parent; }514ScopeKind getKind() const { return Kind; }515516protected:517/// Compiler instance.518Compiler<Emitter> *Ctx;519/// Link to the parent scope.520VariableScope *Parent;521const ValueDecl *ValDecl = nullptr;522ScopeKind Kind;523};524525/// Generic scope for local variables.526template <class Emitter> class LocalScope : public VariableScope<Emitter> {527public:528LocalScope(Compiler<Emitter> *Ctx, ScopeKind Kind = ScopeKind::Block)529: VariableScope<Emitter>(Ctx, nullptr, Kind) {}530LocalScope(Compiler<Emitter> *Ctx, const ValueDecl *VD)531: VariableScope<Emitter>(Ctx, VD) {}532533/// Emit a Destroy op for this scope.534~LocalScope() override {535if (!Idx)536return;537this->Ctx->emitDestroy(*Idx, SourceInfo{});538removeStoredOpaqueValues();539}540541/// Overriden to support explicit destruction.542void emitDestruction() override {543if (!Idx)544return;545546this->emitDestructors();547this->Ctx->emitDestroy(*Idx, SourceInfo{});548}549550/// Explicit destruction of local variables.551bool destroyLocals(const Expr *E = nullptr) override {552if (!Idx)553return true;554555// NB: We are *not* resetting Idx here as to allow multiple556// calls to destroyLocals().557bool Success = this->emitDestructors(E);558this->Ctx->emitDestroy(*Idx, E);559return Success;560}561562void addLocal(const Scope::Local &Local) override {563if (!Idx) {564Idx = this->Ctx->Descriptors.size();565this->Ctx->Descriptors.emplace_back();566this->Ctx->emitInitScope(*Idx, {});567}568569this->Ctx->Descriptors[*Idx].emplace_back(Local);570}571572bool emitDestructors(const Expr *E = nullptr) override {573if (!Idx)574return true;575// Emit destructor calls for local variables of record576// type with a destructor.577for (Scope::Local &Local : llvm::reverse(this->Ctx->Descriptors[*Idx])) {578if (Local.Desc->hasTrivialDtor())579continue;580if (!this->Ctx->emitGetPtrLocal(Local.Offset, E))581return false;582583if (!this->Ctx->emitDestruction(Local.Desc, Local.Desc->getLoc()))584return false;585586if (!this->Ctx->emitPopPtr(E))587return false;588removeIfStoredOpaqueValue(Local);589}590return true;591}592593void removeStoredOpaqueValues() {594if (!Idx)595return;596597for (const Scope::Local &Local : this->Ctx->Descriptors[*Idx]) {598removeIfStoredOpaqueValue(Local);599}600}601602void removeIfStoredOpaqueValue(const Scope::Local &Local) {603if (const auto *OVE =604llvm::dyn_cast_if_present<OpaqueValueExpr>(Local.Desc->asExpr())) {605if (auto It = this->Ctx->OpaqueExprs.find(OVE);606It != this->Ctx->OpaqueExprs.end())607this->Ctx->OpaqueExprs.erase(It);608};609}610611/// Index of the scope in the chain.612std::optional<unsigned> Idx;613};614615/// Scope for storage declared in a compound statement.616// FIXME: Remove?617template <class Emitter> class BlockScope final : public LocalScope<Emitter> {618public:619BlockScope(Compiler<Emitter> *Ctx, ScopeKind Kind = ScopeKind::Block)620: LocalScope<Emitter>(Ctx, Kind) {}621};622623template <class Emitter> class ArrayIndexScope final {624public:625ArrayIndexScope(Compiler<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {626OldArrayIndex = Ctx->ArrayIndex;627Ctx->ArrayIndex = Index;628}629630~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; }631632private:633Compiler<Emitter> *Ctx;634std::optional<uint64_t> OldArrayIndex;635};636637template <class Emitter> class SourceLocScope final {638public:639SourceLocScope(Compiler<Emitter> *Ctx, const Expr *DefaultExpr) : Ctx(Ctx) {640assert(DefaultExpr);641// We only switch if the current SourceLocDefaultExpr is null.642if (!Ctx->SourceLocDefaultExpr) {643Enabled = true;644Ctx->SourceLocDefaultExpr = DefaultExpr;645}646}647648~SourceLocScope() {649if (Enabled)650Ctx->SourceLocDefaultExpr = nullptr;651}652653private:654Compiler<Emitter> *Ctx;655bool Enabled = false;656};657658template <class Emitter> class InitLinkScope final {659public:660InitLinkScope(Compiler<Emitter> *Ctx, InitLink &&Link) : Ctx(Ctx) {661Ctx->InitStack.push_back(std::move(Link));662}663664~InitLinkScope() { this->Ctx->InitStack.pop_back(); }665666private:667Compiler<Emitter> *Ctx;668};669670template <class Emitter> class InitStackScope final {671public:672InitStackScope(Compiler<Emitter> *Ctx, bool Active)673: Ctx(Ctx), OldValue(Ctx->InitStackActive) {674Ctx->InitStackActive = Active;675}676677~InitStackScope() { this->Ctx->InitStackActive = OldValue; }678679private:680Compiler<Emitter> *Ctx;681bool OldValue;682};683684} // namespace interp685} // namespace clang686687#endif688689690