Skip to content

Fix nested break/continue scoping, stack-new sizing, and 3 other lowering bugs#232

Merged
ASDAlexander77 merged 1 commit into
mainfrom
fix/lowering-passes-bugs-2
Jul 14, 2026
Merged

Fix nested break/continue scoping, stack-new sizing, and 3 other lowering bugs#232
ASDAlexander77 merged 1 commit into
mainfrom
fix/lowering-passes-bugs-2

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

Summary

Follow-up to #230's static review of LowerToAffineLoops.cpp/LowerToLLVM.cpp, addressing 5 of the 7 remaining PLAUSIBLE findings tracked in docs/LowerToAffineLoops-LowerToLLVM-review.md.

  • WhileOp/DoWhileOp/ForOp/LabelOp lowering claimed unlabeled break/continue from nested loops via an unbounded region walk, relying on undocumented MLIR dialect-conversion worklist ordering to land on the correct (innermost) target. Replaced with a shared visitBreakContinueInScope walk that stops treating unlabeled break/continue as claimable once it crosses a nested loop/label (or, for break only, switch) boundary, while still finding labeled jumps that legitimately target an outer scope.
  • NewOpLowering's stack-allocation path sized the alloca off the converted pointer type of a class instead of its storage/struct type, allocating only sizeof(ptr) bytes on the stack regardless of the class's actual field layout — a stack under-allocation for any stack-new'd class with fields.
  • SymbolCallInternalOpLowering, LabelOpLowering, SwitchOpLowering each had a debug-only assert guarding a real failure condition (unresolved callee symbol; malformed label/switch region terminator), silently producing malformed IR in release builds. Converted to proper pattern failures (notifyMatchFailure).
  • A cleanup-only TryOp (e.g. from a using declaration with no explicit catch/finally) erased its cleanup block's terminator with nothing replacing it on the Linux/Itanium path. Added the missing landing-pad setup, mirroring the existing Windows and finally-with-cleanup precedent.

Item 8 (Windows landing-pad cleanup filter reusing the typed-catch filter value) is deliberately left alone — the code already self-flags as incomplete (// BUG: in LLVM landing pad is not fully implemented) and a wrong fix risks a worse regression than the status quo. Item 5 (finally-region cloning losing break/continue/try wiring) also remains open, tracked in the review doc.

Test plan

  • cmake --build __build/tslang/windows-msbuild-2026-debug --config Debug -j8 — clean build, no new warnings
  • ctest --test-dir __build/tslang/windows-msbuild-2026-debug -C Debug -j8 — 688/688 passed (JIT + AOT)
  • New test_triple_nested_unlabeled in 00break_continue.ts (3 levels of nested for, innermost unlabeled break/continue) — JIT-executed and checked by value
  • Existing 00disposable.ts/01disposable.ts/02disposable.ts (cleanup-only try via using) — JIT + AOT green, exercising the item 9 fix

- Implemented visitBreakContinueInScope to correctly handle unlabeled break/continue in nested loops.
- Replaced assert with notifyMatchFailure in SymbolCallInternalOpLowering for unresolved callee symbols.
- Adjusted stack allocation in NewOpLowering to use the correct storage type.
- Added test for triple nested unlabeled break/continue behavior.
@ASDAlexander77 ASDAlexander77 merged commit 4fd7408 into main Jul 14, 2026
2 checks passed
@ASDAlexander77 ASDAlexander77 deleted the fix/lowering-passes-bugs-2 branch July 14, 2026 20:01
ASDAlexander77 added a commit that referenced this pull request Jul 15, 2026
A follow-up static audit of LowerToAffineLoops.cpp, LowerToLLVM.cpp, and
the TypeScriptExceptionPass files (beyond the 10 findings already closed
in PRs #230/#232/#233/#234/#235) found and fixes 7 more confirmed bugs:

- SwitchStateOpLowering: generator yield/resume state labels were
  collected into a SmallPtrSet<Operation*,16>, whose iteration order is
  only insertion order below 16 entries; past that it silently falls back
  to pointer-hash order, scrambling the positional switch dispatch used
  by generator resume. Replaced with an order-preserving SmallVector.
- StringConcatOpLowering: the stack-allocation path sized its Alloca
  using a pointer type instead of i8, over-allocating by sizeof(ptr) for
  every multi-argument string concatenation (e.g. console.log with 2+
  args).
- ArraySpliceOpLowering: mixed genuine MLIR index-dialect ops with
  already-LLVM-converted operands, a type mismatch that made every
  Array.prototype.splice() call fail to lower correctly (the only
  .splice() call in the test suite was commented out because of this).
  Reworked to stay consistently in the LLVM-converted domain, matching
  every sibling array-mutation lowering.
- GlobalOpLowering: the side-effect enumeration deciding whether a global
  initializer can be inlined as a constant vs. must run as a real
  constructor was missing several ops with real side effects (array
  push/unshift/splice/pop/shift, delete, set-length, string concat/
  char-to-string).
- LandingPadFixPass: MadeChange was set unconditionally for every
  landingpad visited, even when nothing was rewritten, causing needless
  analysis invalidation on every EH-containing function on every compile.
- Win32ExceptionPass: the PHI-user removal loop erased only the first PHI
  user found then unconditionally erased the underlying value, violating
  LLVM's no-remaining-uses invariant when more than one PHI referenced the
  same to-be-removed value (own TODO comment flagged this as incomplete).
- Win32ExceptionPass: getThrowFn's fallback path created a stray
  _CxxThrowException Function without attaching it to the module.

Added 00array_splice.ts (JIT + AOT) covering shrink/grow/equal-size
splice cases, since this path had zero prior test coverage. Full ctest
suite green: 692/692.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
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