Skip to content

continue a in a: b: for goes on to the next iteration; labelled for-of no longer crashes - #590

Merged
ASDAlexander77 merged 3 commits into
mainfrom
fix-nested-label-continue
Oct 17, 2026
Merged

ASDAlexander77 merged 3 commits into
mainfrom
fix-nested-label-continue

Conversation

@ASDAlexander77

@ASDAlexander77 ASDAlexander77 commented Oct 17, 2026 •

Copy link
Copy Markdown
Owner

Fixes two labelled-loop miscompiles found while fixing silently-accepted bad code (#583 added the unknown-label check; the codegen was already wrong). a: b: for (...) { continue a; } looped forever. a's statement is another label, so mlirGen(LabeledStatement) made a LabelOp for a around the loop, and continue a restarted that region, which runs the loop again from its initializer and skips the incrementor. The outer labels of a chain that ends in a loop are now other names for the innermost one (loopLabelAliases, resolved by break/continue), so the loop carries the only label. A chain that ends in a block keeps its LabelOps, so continue to a labelled block still restarts it (00break_continue.ts). A labelled for-of crashed the compiler on continue b/break b, even with one label (b: for (const v of [1, 2, 3])). Generating the iterated value's iterator generated loops of its own, and they took the pending label before the for that the for-of is made into existed. for and for-of now take the label on entry. The for does this before its initializer, which can generate loops too. Merged with main's #583 label check: break/continue check the label as written, then resolve the alias. Like activeLabels, the aliases are set aside while a nested function is generated, so a function's own a: for inside an outer a: b: for keeps its a.

Expected output is what TypeScript gives: the repro prints 0 2 done. New test 00label_chain_loop.ts (compile + JIT, and in TSLANG_CORPUS): for/while/do/for-of chains, continue a from a nested loop, a one-label for-of over a literal and over an array variable, and a label chain on a block. ### Checked, not fixed here GenContext::loopLabel is always "", as suspected. It is load-bearing (see the comment at scopeExitContinuesOutwards, extended here), and it hides two real scope-exit bugs that need their own change: - continue outer written inside an if in an inner loop stops the scope-exit walk at the inner loop's body, so a using in the outer body is never disposed. - under -mm=rc, a: { s += "x"; break a; } return s; returns "": a break out of a labelled block walks past the function's locals and releases them. This happens with one label too, so it is not from this change, which is why the test's block case has no break. Storing real labels alone is wrong, because the inner loop's context stands in for the outer body scope in that walk. Full ctest -C Release -j 8 --timeout 300: 4098/4098 passed. 🤖 Generated with Claude Code

ASDAlexander77 and others added 3 commits October 17, 2026 15:20
`a`'s statement is another label, so `a` got a LabelOp of its own around the
loop, and `continue a` restarted that region: the loop from its initializer,
skipping the incrementor (an endless loop). The outer labels of a chain that
ends in a loop are now other names for the innermost one, the label the loop
carries; a chain that ends in a block keeps its LabelOps.

A labelled for-of crashed the compiler on `continue`/`break` to its label:
generating the iterated value's iterator generated loops of its own, which
took the pending label before the `for` the loop is made into existed. `for`
and for-of now take the label on entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nto fix-nested-label-continue

# Conflicts:
#	tslang/lib/TypeScript/MLIRGenStatements.cpp
Under rc a jump out of a labelled block releases the function's owned locals (open, not from this change); the string the case built was read after it was freed, which Linux CI caught.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit 34d3d6e into main Oct 17, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the fix-nested-label-continue branch October 17, 2026 15:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant