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 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 VariableScope; 34 template <class Emitter> class DeclScope; 35 template <class Emitter> class InitLinkScope; 36 template <class Emitter> class InitStackScope; 37 template <class Emitter> class OptionScope; 38 template <class Emitter> class ArrayIndexScope; 39 template <class Emitter> class SourceLocScope; 40 template <class Emitter> class LoopScope; 41 template <class Emitter> class LabelScope; 42 template <class Emitter> class SwitchScope; 43 template <class Emitter> class StmtExprScope; 44 45 template <class Emitter> class Compiler; 46 struct InitLink { 47 public: 48 enum { 49 K_This = 0, 50 K_Field = 1, 51 K_Temp = 2, 52 K_Decl = 3, 53 }; 54 ThisInitLink55 static InitLink This() { return InitLink{K_This}; } FieldInitLink56 static InitLink Field(unsigned Offset) { 57 InitLink IL{K_Field}; 58 IL.Offset = Offset; 59 return IL; 60 } TempInitLink61 static InitLink Temp(unsigned Offset) { 62 InitLink IL{K_Temp}; 63 IL.Offset = Offset; 64 return IL; 65 } DeclInitLink66 static InitLink Decl(const ValueDecl *D) { 67 InitLink IL{K_Decl}; 68 IL.D = D; 69 return IL; 70 } 71 InitLinkInitLink72 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. 85 struct VarCreationState { 86 std::optional<bool> S = std::nullopt; 87 VarCreationState() = default; VarCreationStateVarCreationState88 VarCreationState(bool b) : S(b) {} NotCreatedVarCreationState89 static VarCreationState NotCreated() { return VarCreationState(); } 90 91 operator bool() const { return S && *S; } notCreatedVarCreationState92 bool notCreated() const { return !S; } 93 }; 94 95 /// Compilation context for expressions. 96 template <class Emitter> 97 class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>, 98 public Emitter { 99 protected: 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 111 public: 112 /// Initializes the compiler and the backend emitter. 113 template <typename... Tys> Compiler(Context & Ctx,Program & P,Tys &&...Args)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 215 protected: 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 222 protected: 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 classify(const Expr * E)237 std::optional<PrimType> classify(const Expr *E) const { 238 return Ctx.classify(E); 239 } classify(QualType Ty)240 std::optional<PrimType> classify(QualType Ty) const { 241 return Ctx.classify(Ty); 242 } 243 244 /// Classifies a known primitive type. classifyPrim(QualType Ty)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. classifyPrim(const Expr * E)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 296 private: 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); emitConst(const llvm::APInt & 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 getRoundingMode(const Expr * E)327 llvm::RoundingMode getRoundingMode(const Expr *E) const { 328 FPOptions FPO = E->getFPFeaturesInEffect(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); classifyComplexElementType(QualType T)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 356 protected: 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 402 extern template class Compiler<ByteCodeEmitter>; 403 extern template class Compiler<EvalEmitter>; 404 405 /// Scope chain managing the variable lifetimes. 406 template <class Emitter> class VariableScope { 407 public: VariableScope(Compiler<Emitter> * Ctx,const ValueDecl * VD)408 VariableScope(Compiler<Emitter> *Ctx, const ValueDecl *VD) 409 : Ctx(Ctx), Parent(Ctx->VarScope), ValDecl(VD) { 410 Ctx->VarScope = this; 411 } 412 ~VariableScope()413 virtual ~VariableScope() { Ctx->VarScope = this->Parent; } 414 add(const Scope::Local & Local,bool IsExtended)415 void add(const Scope::Local &Local, bool IsExtended) { 416 if (IsExtended) 417 this->addExtended(Local); 418 else 419 this->addLocal(Local); 420 } 421 addLocal(const Scope::Local & Local)422 virtual void addLocal(const Scope::Local &Local) { 423 if (this->Parent) 424 this->Parent->addLocal(Local); 425 } 426 addExtended(const Scope::Local & Local)427 virtual void addExtended(const Scope::Local &Local) { 428 if (this->Parent) 429 this->Parent->addExtended(Local); 430 } 431 addExtended(const Scope::Local & Local,const ValueDecl * ExtendingDecl)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 emitDestruction()450 virtual void emitDestruction() {} emitDestructors()451 virtual bool emitDestructors() { return true; } getParent()452 VariableScope *getParent() const { return Parent; } 453 454 protected: 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. 463 template <class Emitter> class LocalScope : public VariableScope<Emitter> { 464 public: LocalScope(Compiler<Emitter> * Ctx)465 LocalScope(Compiler<Emitter> *Ctx) : VariableScope<Emitter>(Ctx, nullptr) {} LocalScope(Compiler<Emitter> * Ctx,const ValueDecl * VD)466 LocalScope(Compiler<Emitter> *Ctx, const ValueDecl *VD) 467 : VariableScope<Emitter>(Ctx, VD) {} 468 469 /// Emit a Destroy op for this scope. ~LocalScope()470 ~LocalScope() override { 471 if (!Idx) 472 return; 473 this->Ctx->emitDestroy(*Idx, SourceInfo{}); 474 removeStoredOpaqueValues(); 475 } 476 477 /// Overriden to support explicit destruction. emitDestruction()478 void emitDestruction() override { destroyLocals(); } 479 480 /// Explicit destruction of local variables. destroyLocals()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 addLocal(const Scope::Local & Local)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 emitDestructors()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 removeStoredOpaqueValues()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 removeIfStoredOpaqueValue(const Scope::Local & Local)531 void removeIfStoredOpaqueValue(const Scope::Local &Local) { 532 if (const auto *OVE = 533 llvm::dyn_cast_if_present<OpaqueValueExpr>(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. 547 template <class Emitter> class DestructorScope final { 548 public: DestructorScope(LocalScope<Emitter> & OtherScope)549 DestructorScope(LocalScope<Emitter> &OtherScope) : OtherScope(OtherScope) {} 550 ~DestructorScope()551 ~DestructorScope() { OtherScope.emitDestructors(); } 552 553 private: 554 LocalScope<Emitter> &OtherScope; 555 }; 556 557 /// Scope for storage declared in a compound statement. 558 template <class Emitter> class BlockScope final : public LocalScope<Emitter> { 559 public: BlockScope(Compiler<Emitter> * Ctx)560 BlockScope(Compiler<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {} 561 addExtended(const Scope::Local & Local)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 570 template <class Emitter> class ArrayIndexScope final { 571 public: ArrayIndexScope(Compiler<Emitter> * Ctx,uint64_t Index)572 ArrayIndexScope(Compiler<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) { 573 OldArrayIndex = Ctx->ArrayIndex; 574 Ctx->ArrayIndex = Index; 575 } 576 ~ArrayIndexScope()577 ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; } 578 579 private: 580 Compiler<Emitter> *Ctx; 581 std::optional<uint64_t> OldArrayIndex; 582 }; 583 584 template <class Emitter> class SourceLocScope final { 585 public: SourceLocScope(Compiler<Emitter> * Ctx,const Expr * DefaultExpr)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 ~SourceLocScope()595 ~SourceLocScope() { 596 if (Enabled) 597 Ctx->SourceLocDefaultExpr = nullptr; 598 } 599 600 private: 601 Compiler<Emitter> *Ctx; 602 bool Enabled = false; 603 }; 604 605 template <class Emitter> class InitLinkScope final { 606 public: InitLinkScope(Compiler<Emitter> * Ctx,InitLink && Link)607 InitLinkScope(Compiler<Emitter> *Ctx, InitLink &&Link) : Ctx(Ctx) { 608 Ctx->InitStack.push_back(std::move(Link)); 609 } 610 ~InitLinkScope()611 ~InitLinkScope() { this->Ctx->InitStack.pop_back(); } 612 613 private: 614 Compiler<Emitter> *Ctx; 615 }; 616 617 template <class Emitter> class InitStackScope final { 618 public: InitStackScope(Compiler<Emitter> * Ctx,bool Active)619 InitStackScope(Compiler<Emitter> *Ctx, bool Active) 620 : Ctx(Ctx), OldValue(Ctx->InitStackActive) { 621 Ctx->InitStackActive = Active; 622 } 623 ~InitStackScope()624 ~InitStackScope() { this->Ctx->InitStackActive = OldValue; } 625 626 private: 627 Compiler<Emitter> *Ctx; 628 bool OldValue; 629 }; 630 631 } // namespace interp 632 } // namespace clang 633 634 #endif 635