Index: clang/lib/AST/Interp/ByteCodeExprGen.h =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ clang/lib/AST/Interp/ByteCodeExprGen.h @@ -29,6 +29,7 @@ namespace interp { template class LocalScope; +template class DestructorScope; template class RecordScope; template class VariableScope; template class DeclScope; @@ -189,6 +190,7 @@ private: friend class VariableScope; friend class LocalScope; + friend class DestructorScope; friend class RecordScope; friend class DeclScope; friend class OptionScope; @@ -306,7 +308,7 @@ } virtual void emitDestruction() {} - + virtual void emitDestructors() {} VariableScope *getParent() const { return Parent; } protected: @@ -316,15 +318,26 @@ VariableScope *Parent; }; -/// Scope for local variables. -/// -/// When the scope is destroyed, instructions are emitted to tear down -/// all variables declared in this scope. +/// Generic scope for local variables. template class LocalScope : public VariableScope { public: LocalScope(ByteCodeExprGen *Ctx) : VariableScope(Ctx) {} - ~LocalScope() override { this->emitDestruction(); } + /// Emit a Destroy op for this scope. + ~LocalScope() override { + if (!Idx) + return; + this->Ctx->emitDestroy(*Idx, SourceInfo{}); + } + + /// Overriden to support explicit destruction. + void emitDestruction() override { + if (!Idx) + return; + this->emitDestructors(); + this->Ctx->emitDestroy(*Idx, SourceInfo{}); + this->Idx = std::nullopt; + } void addLocal(const Scope::Local &Local) override { if (!Idx) { @@ -335,9 +348,7 @@ this->Ctx->Descriptors[*Idx].emplace_back(Local); } - /// Emit destruction of the local variable. This includes - /// object destructors. - void emitDestruction() override { + void emitDestructors() override { if (!Idx) return; // Emit destructor calls for local variables of record @@ -348,19 +359,40 @@ this->Ctx->emitRecordDestruction(Local.Desc); } } - - this->Ctx->emitDestroy(*Idx, SourceInfo{}); } -protected: /// Index of the scope in the chain. std::optional Idx; }; +/// Emits the destructors of the variables of \param OtherScope +/// when this scope is destroyed. Does not create a Scope in the bytecode at +/// all, this is just a RAII object to emit destructors. +template class DestructorScope final { +public: + DestructorScope(LocalScope &OtherScope) : OtherScope(OtherScope) {} + + ~DestructorScope() { OtherScope.emitDestructors(); } + +private: + LocalScope &OtherScope; +}; + +/// Like a regular LocalScope, except that the destructors of all local +/// variables are automatically emitted when the AutoScope is destroyed. +template class AutoScope : public LocalScope { +public: + AutoScope(ByteCodeExprGen *Ctx) + : LocalScope(Ctx), DS(*this) {} + +private: + DestructorScope DS; +}; + /// Scope for storage declared in a compound statement. -template class BlockScope final : public LocalScope { +template class BlockScope final : public AutoScope { public: - BlockScope(ByteCodeExprGen *Ctx) : LocalScope(Ctx) {} + BlockScope(ByteCodeExprGen *Ctx) : AutoScope(Ctx) {} void addExtended(const Scope::Local &Local) override { // If we to this point, just add the variable as a normal local @@ -372,9 +404,9 @@ /// Expression scope which tracks potentially lifetime extended /// temporaries which are hoisted to the parent scope on exit. -template class ExprScope final : public LocalScope { +template class ExprScope final : public AutoScope { public: - ExprScope(ByteCodeExprGen *Ctx) : LocalScope(Ctx) {} + ExprScope(ByteCodeExprGen *Ctx) : AutoScope(Ctx) {} void addExtended(const Scope::Local &Local) override { if (this->Parent) Index: clang/lib/AST/Interp/ByteCodeStmtGen.h =================================================================== --- clang/lib/AST/Interp/ByteCodeStmtGen.h +++ clang/lib/AST/Interp/ByteCodeStmtGen.h @@ -54,6 +54,7 @@ // Statement visitors. bool visitStmt(const Stmt *S); bool visitCompoundStmt(const CompoundStmt *S); + bool visitLoopBody(const Stmt *S); bool visitDeclStmt(const DeclStmt *DS); bool visitReturnStmt(const ReturnStmt *RS); bool visitIfStmt(const IfStmt *IS); Index: clang/lib/AST/Interp/ByteCodeStmtGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -194,6 +194,23 @@ } } +/// Visits the given statment without creating a variable +/// scope for it in case it is a compound statement. +template +bool ByteCodeStmtGen::visitLoopBody(const Stmt *S) { + if (isa(S)) + return true; + + if (const auto *CS = dyn_cast(S)) { + for (auto *InnerStmt : CS->body()) + if (!visitStmt(InnerStmt)) + return false; + return true; + } + + return this->visitStmt(S); +} + template bool ByteCodeStmtGen::visitCompoundStmt( const CompoundStmt *CompoundStmt) { @@ -306,11 +323,15 @@ if (!this->jumpFalse(EndLabel)) return false; - if (!this->visitStmt(Body)) - return false; + LocalScope Scope(this); + { + DestructorScope DS(Scope); + if (!this->visitLoopBody(Body)) + return false; + } + if (!this->jump(CondLabel)) return false; - this->emitLabel(EndLabel); return true; @@ -325,15 +346,21 @@ LabelTy EndLabel = this->getLabel(); LabelTy CondLabel = this->getLabel(); LoopScope LS(this, EndLabel, CondLabel); + LocalScope Scope(this); this->emitLabel(StartLabel); - if (!this->visitStmt(Body)) - return false; - this->emitLabel(CondLabel); - if (!this->visitBool(Cond)) - return false; + { + DestructorScope DS(Scope); + + if (!this->visitLoopBody(Body)) + return false; + this->emitLabel(CondLabel); + if (!this->visitBool(Cond)) + return false; + } if (!this->jumpTrue(StartLabel)) return false; + this->emitLabel(EndLabel); return true; } @@ -350,6 +377,7 @@ LabelTy CondLabel = this->getLabel(); LabelTy IncLabel = this->getLabel(); LoopScope LS(this, EndLabel, IncLabel); + LocalScope Scope(this); if (Init && !this->visitStmt(Init)) return false; @@ -360,11 +388,17 @@ if (!this->jumpFalse(EndLabel)) return false; } - if (Body && !this->visitStmt(Body)) - return false; - this->emitLabel(IncLabel); - if (Inc && !this->discard(Inc)) - return false; + + { + DestructorScope DS(Scope); + + if (Body && !this->visitLoopBody(Body)) + return false; + this->emitLabel(IncLabel); + if (Inc && !this->discard(Inc)) + return false; + } + if (!this->jump(CondLabel)) return false; this->emitLabel(EndLabel); @@ -386,38 +420,40 @@ LabelTy CondLabel = this->getLabel(); LabelTy IncLabel = this->getLabel(); LoopScope LS(this, EndLabel, IncLabel); - { - ExprScope ES(this); - // Emit declarations needed in the loop. - if (Init && !this->visitStmt(Init)) - return false; - if (!this->visitStmt(RangeStmt)) - return false; - if (!this->visitStmt(BeginStmt)) - return false; - if (!this->visitStmt(EndStmt)) - return false; + // Emit declarations needed in the loop. + if (Init && !this->visitStmt(Init)) + return false; + if (!this->visitStmt(RangeStmt)) + return false; + if (!this->visitStmt(BeginStmt)) + return false; + if (!this->visitStmt(EndStmt)) + return false; - // Now the condition as well as the loop variable assignment. - this->emitLabel(CondLabel); - if (!this->visitBool(Cond)) - return false; - if (!this->jumpFalse(EndLabel)) - return false; + // Now the condition as well as the loop variable assignment. + this->emitLabel(CondLabel); + if (!this->visitBool(Cond)) + return false; + if (!this->jumpFalse(EndLabel)) + return false; - if (!this->visitVarDecl(LoopVar)) - return false; + if (!this->visitVarDecl(LoopVar)) + return false; + + // Body. + LocalScope Scope(this); + { + DestructorScope DS(Scope); - // Body. - if (!this->visitStmt(Body)) + if (!this->visitLoopBody(Body)) return false; this->emitLabel(IncLabel); if (!this->discard(Inc)) return false; - if (!this->jump(CondLabel)) - return false; } + if (!this->jump(CondLabel)) + return false; this->emitLabel(EndLabel); return true; @@ -428,7 +464,7 @@ if (!BreakLabel) return false; - this->emitCleanup(); + this->VarScope->emitDestructors(); return this->jump(*BreakLabel); } @@ -437,7 +473,7 @@ if (!ContinueLabel) return false; - this->emitCleanup(); + this->VarScope->emitDestructors(); return this->jump(*ContinueLabel); }