Skip to content

Commit 52b7e85

Browse files
committed
[clang][bytecode] Fix an inconsistency with loop condition jumps
When emitting the jump for e.g. a for loop condition, we used to jump out of the CondScope, leaving the scope initialized, because we skipped the corresponding Destroy opcode. If that loop was in a loop itself, that outer loop could then iterate once more, leading to us initializing a scope that was still initialized. Fix this by also destroying the scope after the EndLabel.
1 parent fafeaab commit 52b7e85

File tree

2 files changed

+18
-16
lines changed

2 files changed

+18
-16
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5431,21 +5431,21 @@ bool Compiler<Emitter>::visitForStmt(const ForStmt *S) {
54315431
this->fallthrough(CondLabel);
54325432
this->emitLabel(CondLabel);
54335433

5434-
{
5435-
LocalScope<Emitter> CondScope(this);
5436-
if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt())
5437-
if (!visitDeclStmt(CondDecl))
5438-
return false;
5434+
// Start of loop body.
5435+
LocalScope<Emitter> CondScope(this);
5436+
if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt())
5437+
if (!visitDeclStmt(CondDecl))
5438+
return false;
54395439

5440-
if (Cond) {
5441-
if (!this->visitBool(Cond))
5442-
return false;
5443-
if (!this->jumpFalse(EndLabel))
5444-
return false;
5445-
}
5440+
if (!this->maybeEmitDeferredVarInit(S->getConditionVariable()))
5441+
return false;
54465442

5447-
if (!this->maybeEmitDeferredVarInit(S->getConditionVariable()))
5443+
if (Cond) {
5444+
if (!this->visitBool(Cond))
5445+
return false;
5446+
if (!this->jumpFalse(EndLabel))
54485447
return false;
5448+
}
54495449

54505450
if (Body && !this->visitStmt(Body))
54515451
return false;
@@ -5457,13 +5457,14 @@ bool Compiler<Emitter>::visitForStmt(const ForStmt *S) {
54575457

54585458
if (!CondScope.destroyLocals())
54595459
return false;
5460-
}
54615460
if (!this->jump(CondLabel))
54625461
return false;
5462+
// End of loop body.
54635463

5464-
this->fallthrough(EndLabel);
54655464
this->emitLabel(EndLabel);
5466-
return true;
5465+
// If we jumped out of the loop above, we still need to clean up the condition
5466+
// scope.
5467+
return CondScope.destroyLocals();
54675468
}
54685469

54695470
template <class Emitter>

clang/lib/AST/ByteCode/Compiler.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,9 +531,10 @@ template <class Emitter> class LocalScope : public VariableScope<Emitter> {
531531
if (!Idx)
532532
return true;
533533

534+
// NB: We are *not* resetting Idx here as to allow multiple
535+
// calls to destroyLocals().
534536
bool Success = this->emitDestructors(E);
535537
this->Ctx->emitDestroy(*Idx, E);
536-
this->Idx = std::nullopt;
537538
return Success;
538539
}
539540

0 commit comments

Comments
 (0)