Skip to content

tsbindgen: lay out std::string, static_vector and the other fields it skipped - #564

Merged
ASDAlexander77 merged 1 commit into
mainfrom
tsbindgen-library-fields
Oct 13, 2026
Merged

ASDAlexander77 merged 1 commit into
mainfrom
tsbindgen-library-fields

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

A struct's tuple now spells every field C++ lays out, so structs holding library types are tuples with that library's layout instead of Opaque.

What changes

  • Specializations held by value are declared, named by their arguments: std::string → basic_string_char, nvrhi::static_vector<IBindingSet *, 8> → static_vector_IBindingSet_8, RefCountPtr<IShader> → RefCountPtr_IShader = [ptr_: IShader | null]. A pointer to a specialization alone stays Opaque /* ... */.
  • Bases: a derived struct has its bases' fields first (an empty base has none). MSVC's tail padding after a base becomes a _pad field; the Itanium ABI's reuse of it is kept.
  • Arrays: T x[N] → x: [_0: T, ..., _{N-1}: T] (up to 1024 elements; tslang has no fixed-size array type).
  • Unions: the first member when it alone has the union's size and alignment, raw words otherwise (union { char buf[16]; char *ptr; } → [_0: u64, _1: u64]). Anonymous unions are named after their first member; anonymous structs are flattened.
  • Bitfields: a run is raw words over its bytes, named after its first bitfield.
  • [[no_unique_address]] empty members take no storage (libc++'s string allocator).
  • One layout pass (spellRecord) both decides and spells, for recordSkipReason and mapFields.
  • Fix: a struct aligned beyond its fields (alignas, DECLSPEC_ALIGN(16)) is now skipped — a tuple holding it would have been placed at the wrong offset.
  • Fix: an operator with C linkage (guiddef.h's operator== for GUID) is no longer emitted as a nameless declare function (...).

Member names inside library types are that library's own and differ between MSVC's STL and libc++ (_Elems vs __elems_); tuple literals are positional, so only name-based reads are per-ABI.

Results

NVRHI: every desc is now a tuple. BufferDesc is 80 bytes under MSVC and 72 under libc++, matching C++ (nvrhi.layoutMatches()).

Tests

  • New LayoutTest.cpp (arrays, bitfields, unions, held specializations, MSVC- and libc++-shaped std::string, base tail padding, inherited name clashes — under both windowsTarget and linuxTarget), Naming.OperatorWithCLinkageIsLeftOut; flipped expectations in SkipTest/NamespacedStructTest. 76/76.
  • test-bindgen-cpp: the fixture passes a static_vector-shaped container (private array base + count), a buffer/pointer union and a bitfield run to real compiled C++ (exe + JIT). ctest -R "test-bindgen|cppvtable|cpp_slot": 46/46.
  • Generated and compiled with tslang: NVRHI (MSVC, Android x86_64/aarch64), the MSVC STL and libc++ (--filter 'std::*').
  • native_ts_graphics with every NVRHI struct generated (hand tuples removed): nvrhi_direct + headless pass on Windows (dx12/vk, AOT + JIT, -debug) and the Android emulator (x86_64, arm64).

Found, not fixed

  • A type used before its declaration (including through Reference<X>) fails in tslang: windows.h + d3d12.h give 284 such errors with both this and the previous tsbindgen. Sorting the output by dependency is a follow-up.
  • @cpp class fields (addClassFields) don't use the layout pass yet: a union or bitfield in a class still drops its fields. NVRHI's interfaces have none.
  • On Android, plain char arrays are s8 on x86_64 and u8 on aarch64 (faithful; same layout).

Downstream

native_ts_graphics' branch nvrhi-generated-descs uses this (generated descs, hand tuples removed); it will be opened after a tslang with this change is deployed. Native main keeps building in the meantime.

🤖 Generated with Claude Code

- Updated `nameFromKey` to correctly handle template arguments in names.
- Modified `Collector` to ensure operators without names are excluded from declarations.
- Introduced new functions in `TypeMapper` to handle template specializations and instantiations.
- Enhanced `mapType` to support arrays and bitfields, ensuring proper layout representation.
- Added tests for struct layouts, including arrays, unions, and specializations.
- Updated `fixture_cpp` and `bindgen_cpp_test` to reflect changes in type mappings and added functionality.
- Improved handling of derived structs and template specializations in namespaced contexts.
@ASDAlexander77
ASDAlexander77 merged commit aa76dfa into main Oct 13, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the tsbindgen-library-fields branch October 13, 2026 00:02
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