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