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