Skip to content

@cpp classes: @slot(N) makes a method a C++ virtual method in slot N - #561

Merged
ASDAlexander77 merged 1 commit into
mainfrom
cppvtable-slot
Oct 12, 2026
Merged

ASDAlexander77 merged 1 commit into
mainfrom
cppvtable-slot

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

A @cppvtable class numbered its methods as vtable slots by declaration order, so a binding had to declare a placeholder for every slot it didn't call, overloads (which MSVC orders its own way) were numbered by hand, and a slot off by one called another C++ method with no error.

The decorator is now @cpp, and only a method with @slot(N) is virtual:

Method in a @cpp class Meaning
@slot(N) f(): T; C++ virtual method, slot N (base slots counted); any order, gaps allowed
f(): T; named like a base's slot override: keeps that slot, as in C++
@linkname("?f@C@@QEAAHH@Z") f(): T; C++ non-virtual method, called by its symbol as fn(this, args)
f(): T { ... } without @slot TypeScript's own helper, not in the vtable
  • Skipped slots are null in a class implementing C++ methods; two methods in one slot are an error.
  • Errors: a bodiless method with neither @slot nor @linkname (a forgotten @slot isn't a silent wrong call), an abstract method without @slot, an override's @slot not matching its base's, @slot on an ordinary class, a non-virtual C++ method returning a struct (not supported yet).
  • @cppvtable is an error saying it is now @cpp: an unknown decorator would have left an old binding an ordinary class.
  • Ordinary classes are unchanged. Exported @cpp classes carry each method's @slot in their declarations.

Breaking: existing @cppvtable bindings (native_ts_graphics core/nvrhi.ts) must move to @cpp + @slot(N) before they're built with a tslang that has this.

Tests

  • Existing @cpp tests converted to @slot with their positional numbers.
  • tests/00cpp_slot.ts: out-of-order and skipped slots, a derived class, a TypeScript helper (AOT and JIT).
  • test-jit-cppvtable-abi: calls a real non-virtual C++ method by its MSVC / Itanium mangled name; Counter gets a TypeScript helper (the Itanium vtable check still sees only the C++ slots).
  • The export/import test calls a helper across modules.
  • One compile-error test per new rule.
  • Full suite (windows-msbuild-2026-release): 4042/4042 passed (1 already disabled).

Docs: docs/cppvtable-classes.md becomes docs/cpp-classes.md.

🤖 Generated with Claude Code

A @cppvtable class numbered its methods as vtable slots by declaration
order, so a binding had to declare a placeholder for every slot it
didn't call, overloads (which MSVC orders its own way) were numbered by
hand, and a slot off by one called another C++ method with no error.

The decorator is now @cpp, and only a method with @slot(N) is virtual:
slot N of the vtable, a base class's slots counted, in any order. The
slots no method names are skipped (null in a class implementing C++
methods), so a binding declares only what it calls; two methods in one
slot are an error. As in C++, a method overriding a base's slot by name
keeps that slot without @slot. A method without @slot isn't virtual:
with a body it is TypeScript's own (a helper, not in the vtable, and it
no longer makes the class an implementation of C++ methods); without
one it is a C++ non-virtual method, called by the symbol @Linkname gives
it, as fn(this, args) with C++'s argument extension. A bodiless method
with neither @slot nor @Linkname, and an abstract one without @slot, are
errors, so a forgotten @slot isn't a silent wrong call. Exported classes
carry each method's @slot in their declarations.

@cppvtable is an error saying it is now @cpp: an unknown decorator would
have left an old binding an ordinary class. Ordinary classes are
unchanged; @slot on one is an error. A non-virtual C++ method returning
a struct isn't supported yet (an error).

The existing tests move to @cpp with their positional slots, the ABI
tests call a real non-virtual C++ method by its MSVC / Itanium mangled
name and give Counter a TypeScript helper, the export/import test calls
a helper across modules, and docs/cppvtable-classes.md
becomes docs/cpp-classes.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit 5223e36 into main Oct 12, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the cppvtable-slot branch October 12, 2026 20:22
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