Skip to content

Catch a class thrown from another module (Linux box thunk, -shared instanceof, thunk linkage) - #351

Merged
ASDAlexander77 merged 1 commit into
mainfrom
fix-linux-cross-module-class-catch
Sep 23, 2026
Merged

ASDAlexander77 merged 1 commit into
mainfrom
fix-linux-cross-module-class-catch

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

Summary

An untyped or any catch of a class that only another module throws failed on both platforms. Fixing it exposed three more bugs on the same path.

  • Linux: a thrown class now carries its own box thunk. The untyped catch only recognised classes its own module throws (the ts.thrown_classes list). Any other class was boxed as a plain object, so <Cls>e threw "Can't cast from any type".
    • The thrower now supplies the box, as the Windows copy thunk does. The class's _ZTIP<n><name> (a __pointer_type_info) gets a fifth field that libstdc++ never reads: the address of an .eh.copy.box.P<n><name> thunk (class → any). It is built by the existing mlirGenCatchCopyThunk.
    • When the untyped catch sees a __pointer_type_info, it calls that thunk. Anything else, such as a foreign C++ exception, is still boxed as a plain object.
    • This replaces ts.thrown_classes and recordThrownClass.
  • -shared: instanceof and <C>anyValue of an imported class. mlirGenInstanceOfOpaque expected the rtti of a dynamically imported class to be a ref. The property access already reads through it, so the check failed and the .instanceOf call was dropped: x instanceof C did not compile, and <C>e always threw.
  • Windows, static link: duplicate .eh.copy.box.* symbol. A typed catch and the throw each emitted the thunk as an external function. Thunks now have internal linkage. linkonce_odr + comdat (the specialization path) fixed the link but made JIT catches crash with an access violation.
  • if (x instanceof N.C) crashed the compiler for any namespaced class, even in a single module. The narrowing built a type reference from the property access instead of a qualified name.

Notes

  • ABI: the layout of tslang's class type_info changes on Linux. linkonce_odr copies must agree, so objects built by an older compiler, such as a prebuilt DefaultLib, must be rebuilt.
  • Not fixed here: MLIRCodeLogicHelper::conditionalValue returns failure but leaves its half-built ts.If in the IR. That is how the dropped instanceOf call became "'ts.If' op expects a non-empty block", or an unbox that always throws, with no error message.

Tests

  • New: import_throw_class.ts / export_throw_class.ts. Registered like class-extends: static, -shared, -jit -shared, plus the rc/none variants. They cover a typed catch, <C>e in an untyped catch, <C>e in an any catch, and instanceof narrowing.
  • New: 00instanceof_namespace_narrowing.ts.
  • Windows Release: 2843/2843 passed.
  • Linux (WSL): 2837/2837 passed.

🤖 Generated with Claude Code

…stanceof, thunk linkage

An untyped or `any` catch of a class that only another module throws did not
work on either platform:

- Linux: the catch-all binding recognised only the classes its own module
  throws (ts.thrown_classes), so any other class was boxed as a plain object
  and `<Cls>e` threw "Can't cast from any type". The thrower now supplies the
  box, as the Windows copy thunk does: a class's __pointer_type_info gets a
  fifth field, the address of a `.eh.copy.box.P<n><name>` thunk (class ->
  any), which the binding calls when the type_info is a __pointer_type_info.
  This replaces the ts.thrown_classes list.
- -shared: `x instanceof C` and `<C>anyValue` of a class imported from a
  shared library expected its rtti value to be a ref, and failed when the
  property access had already read through it - so the instanceOf call was
  dropped: `instanceof` did not compile and the cast always threw.
- Windows, static link: a typed catch and the throw each emitted the class's
  `.eh.copy.box` thunk as an external symbol - duplicate symbol. Thunks are now
  internal (linkonce_odr crashed catches under the Win64 JIT).

Also fixes `if (x instanceof N.C)` for a namespaced class, which crashed the
compiler: the narrowing built a type reference from the property access
instead of a qualified name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit 6aa5f44 into main Sep 23, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the fix-linux-cross-module-class-catch branch September 23, 2026 16:27
ASDAlexander77 added a commit that referenced this pull request Sep 23, 2026
…#352)

MLIRCodeLogicHelper::conditionalValue returned failure with its IfOp still in
the IR - an empty or none-typed region - and the insertion point still inside
it. Whenever the caller carried on, the failure turned into bad IR further on:
"'ts.If' op expects a non-empty block" in place of the branch's own error
(seen as `x instanceof C` of a -shared class before #351). It now erases the
IfOp and puts the insertion point back before returning.

Co-authored-by: Claude Opus 5.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