Index: clang/lib/AST/Interp/ByteCodeExprGen.h =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ clang/lib/AST/Interp/ByteCodeExprGen.h @@ -306,6 +306,8 @@ } virtual void emitDestruction() {} + /// Emit destructors for local variables in this scope. + virtual void emitDestructors() {} VariableScope *getParent() const { return Parent; } @@ -316,15 +318,25 @@ 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{}); + } void addLocal(const Scope::Local &Local) override { if (!Idx) { @@ -335,9 +347,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,8 +358,6 @@ this->Ctx->emitRecordDestruction(Local.Desc); } } - - this->Ctx->emitDestroy(*Idx, SourceInfo{}); } protected: @@ -357,10 +365,19 @@ std::optional Idx; }; +/// 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) {} + + ~AutoScope() override { this->emitDestructors(); } +}; + /// 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 +389,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 visitUnscopedCompoundStmt(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,21 @@ } } +template +bool ByteCodeStmtGen::visitUnscopedCompoundStmt(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 +321,13 @@ if (!this->jumpFalse(EndLabel)) return false; - if (!this->visitStmt(Body)) + LocalScope Scope(this); + if (!this->visitUnscopedCompoundStmt(Body)) return false; + + Scope.emitDestructors(); if (!this->jump(CondLabel)) return false; - this->emitLabel(EndLabel); return true; @@ -325,13 +342,16 @@ LabelTy EndLabel = this->getLabel(); LabelTy CondLabel = this->getLabel(); LoopScope LS(this, EndLabel, CondLabel); + LocalScope Scope(this); this->emitLabel(StartLabel); - if (!this->visitStmt(Body)) + if (!this->visitUnscopedCompoundStmt(Body)) return false; this->emitLabel(CondLabel); if (!this->visitBool(Cond)) return false; + + Scope.emitDestructors(); if (!this->jumpTrue(StartLabel)) return false; this->emitLabel(EndLabel); @@ -350,6 +370,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 +381,13 @@ if (!this->jumpFalse(EndLabel)) return false; } - if (Body && !this->visitStmt(Body)) + if (Body && !this->visitUnscopedCompoundStmt(Body)) return false; this->emitLabel(IncLabel); if (Inc && !this->discard(Inc)) return false; + + Scope.emitDestructors(); if (!this->jump(CondLabel)) return false; this->emitLabel(EndLabel); @@ -386,38 +409,38 @@ 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. - if (!this->visitStmt(Body)) - return false; - this->emitLabel(IncLabel); - if (!this->discard(Inc)) - return false; - if (!this->jump(CondLabel)) - return false; - } + // Body. + LocalScope Scope(this); + if (!this->visitUnscopedCompoundStmt(Body)) + return false; + this->emitLabel(IncLabel); + if (!this->discard(Inc)) + return false; + + Scope.emitDestructors(); + if (!this->jump(CondLabel)) + return false; this->emitLabel(EndLabel); return true; @@ -428,7 +451,7 @@ if (!BreakLabel) return false; - this->emitCleanup(); + this->VarScope->emitDestructors(); return this->jump(*BreakLabel); } @@ -437,7 +460,7 @@ if (!ContinueLabel) return false; - this->emitCleanup(); + this->VarScope->emitDestructors(); return this->jump(*ContinueLabel); }