|  | # Thunks for class template member functions | 
|  |  | 
|  | ## Problem definition | 
|  |  | 
|  | Given the C++ header below... | 
|  |  | 
|  | ```cpp | 
|  | #pragma clang lifetime_elision | 
|  |  | 
|  | template <typename T> | 
|  | class MyTemplate { | 
|  | public: | 
|  | MyTemplate(T value) : value_(value) {} | 
|  | const T& GetValue() const; | 
|  | private: | 
|  | T value_; | 
|  | }; | 
|  |  | 
|  | using MyIntTemplate = MyTemplate<int>; | 
|  | ``` | 
|  |  | 
|  | ... Crubit will generate Rust bindings that can call into the | 
|  | `MyTemplate<int>::GetValue()` member function. To support such calls, Crubit has | 
|  | to generate a C++ *thunk* (to *instantiate* the class template and to provide a | 
|  | symbol for a C-ABI-compatible function that Rust can call into): | 
|  |  | 
|  | ```cpp | 
|  | extern "C"  // <- C ABI | 
|  | int const& __rust_thunk___ZNK10MyTemplateIiE8GetValueEv( | 
|  | const class MyTemplate<int>* __this) { | 
|  | return __this->GetValue(); | 
|  | } | 
|  | ``` | 
|  |  | 
|  | There are other (non-`template`-related) scenarios that require generating | 
|  | thunks (e.g. `inline` functions, or functions that use a custom calling | 
|  | convention), but templates bring one extra requirement: a class template can | 
|  | be defined in one header (say `my_template.h`) and used in *multiple* other | 
|  | headers (e.g. `library_foo/template_user1.h` and | 
|  | `library_bar/template_user2.h`). Because of this, the same thunk might need to | 
|  | be present in *multiple* generated `..._rs_api_impl.cc` files (e.g. in | 
|  | `library_foo_rs_api_impl.cc` and `library_bar_rs_api_impl.cc`). This may lead to | 
|  | duplicate symbol errors from the linker: | 
|  |  | 
|  | ```stderr | 
|  | ld: error: duplicate symbol: __rust_thunk___ZNK10MyTemplateIiE8GetValueEv | 
|  | ``` | 
|  |  | 
|  | ## Implemented solution: Encoding target name in the thunk name | 
|  |  | 
|  | One solution is to give each of the generated thunks a unique, | 
|  | target/library-specific name, e.g.: | 
|  | `__rust_thunk___ZNK10MyTemplateIiE8GetValueEv__library_foo` (note the | 
|  | `library_foo` suffix). | 
|  |  | 
|  | Pros: | 
|  |  | 
|  | -   **Minimal extra code complexity** (e.g. no need for templates-specific code | 
|  | in thunk-related code in `src_code_gen.rs`). | 
|  | -   **Obviously correct behavior-wise** (e.g. since it is just like other thunks | 
|  | which we assume are implemented correctly). | 
|  |  | 
|  | Cons: | 
|  |  | 
|  | -   **Performance guarantees are unclear**. Binary size depends on link time | 
|  | optimization (LTO) recognizing that all the thunks are identical and | 
|  | deduplicating them. | 
|  |  | 
|  | -   This seems to work in practice (at least for production binaries). | 
|  | -   Future work: add tests + consider asking LLVM to provide LTO guarantees | 
|  |  | 
|  | -   **Requires escaping Bazel target names** into valid C identifiers. See | 
|  | `ConvertToCcIdentifier(const BazelLabel&)` in `bazel_types.cc`. | 
|  |  | 
|  | ## Alternative solutions | 
|  |  | 
|  | ### Function template | 
|  |  | 
|  | An alternative solution would be to use a function template that we immediately | 
|  | explicitly instantiate. These still generate the code we need, but their | 
|  | duplicated symbol definitions (across multiple binding crates) won't cause an | 
|  | ODR violation. It is expected that a single function template is instantiated | 
|  | multiple times in multiple translation units, therefore the linker silently | 
|  | merges these equivalent definitions. | 
|  |  | 
|  | Example: | 
|  |  | 
|  | ```cpp | 
|  | // Thunk is expressed as a function template: | 
|  | template <typename = void> | 
|  | __attribute__((__always_inline__)) int const& | 
|  | __rust_thunk___ZNK10MyTemplateIiE8GetValueEv( | 
|  | const class MyTemplate<int>* __this) { | 
|  | return __this->GetValue(); | 
|  | } | 
|  |  | 
|  | // Explicit instantiation of the function template: | 
|  | // (to generate a symbol that `..._rs_api.rs` can call into) | 
|  | template int const& __rust_thunk___ZNK10MyTemplateIiE8GetValueEv( | 
|  | const class MyTemplate<int>* __this); | 
|  | ``` | 
|  |  | 
|  | Pros: | 
|  |  | 
|  | -   **Naturally deduplicated** (just depending on what C++ already does for | 
|  | function templates). | 
|  |  | 
|  | Cons: | 
|  |  | 
|  | -   **Assumes a particular ABI** - a function template specialization uses the | 
|  | calling convention prescribed by the platform C++ ABI.  We know that | 
|  | [the Itanium ABI maps C++ sigatures to the C | 
|  | ABI](https://itanium-cxx-abi.github.io/cxx-abi/abi.html#functions) and | 
|  | therefore will be compatible with the calling convention expected by the | 
|  | generated `..._rs_api.rs`.  Further research is needed to investigate the | 
|  | guarantees offered by other platforms (e.g., the MSVC ABI). | 
|  | -   **Requires extra complexity** to calculate the mangled name of the function | 
|  | template specialization. | 
|  | -   Crubit doesn’t have a `clang::FunctionDecl` corresponding to the | 
|  | function-template-based thunk, and therefore Crubit can’t use | 
|  | `clang::MangleContext::mangleName` to calculate the linkable/mangled | 
|  | name of the thunk. | 
|  | -   Reimplementing `clang::MangleContext::mangleName` in Crubit seems | 
|  | fragile. One risk is bugs in Crubit's code that would make it behave | 
|  | differently from Clang (e.g. code review of the initial prototype | 
|  | identified that | 
|  | [mangling compression](https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression) | 
|  | was missing). Another risk is having to implement not just | 
|  | `ItaniumMangleContext`, but also `MicrosoftMangleContext`. | 
|  | -   One idea to avoid reimpliementing mangling is to explicitly specify | 
|  | the name for the function template instantiation using | 
|  | `__asm__("abc")` (sadly this doesn't seem to work - it may be a | 
|  | Clang bug). | 
|  |  | 
|  | An abandoned prototype of this approach can be found in a (Google-internal) | 
|  | cl/450495903. | 
|  |  | 
|  | ### Explicit `linkonce_odr` attribute | 
|  |  | 
|  | Example: | 
|  |  | 
|  | ```cpp | 
|  | extern "C" | 
|  | int const& __rust_thunk___ZNK10MyTemplateIiE8GetValueEv( | 
|  | const class MyTemplate<int>* __this) | 
|  | __attribute__((linkonce_odr))  // <- THIS IS THE PROPOSAL | 
|  | { | 
|  | return __this->GetValue(); | 
|  | } | 
|  | ``` | 
|  |  | 
|  | Pros: | 
|  |  | 
|  | -   All the "pros" of the "Encoding target name in the thunk name" approach | 
|  | (simplicity + correctness of behavior) | 
|  | -   All the "pros" of the "Function template" template approach (deduplication) | 
|  |  | 
|  | Cons: | 
|  |  | 
|  | -   Requires changing Clang to support the new attribute (e.g. requires | 
|  | convincing the Clang community that this is a language extension that is | 
|  | worth supporting). | 
|  | **TODO(b/234889162)**: Send out a short RFC to gauge interest? | 
|  |  | 
|  | ## Rejected solutions | 
|  |  | 
|  | -   [`selectany`](https://clang.llvm.org/docs/AttributeReference.html#selectany) | 
|  | doesn't work with functions, only data members. Furthermore, we need | 
|  | something that maps to `linkonce_odr`, and selectany maps only to | 
|  | `linkonce`. | 
|  |  | 
|  | -   `__attribute__((weak))` has the disadvantage that a weak definition can be | 
|  | overridden by a strong one. This rule makes weak definitions non-inlineable | 
|  | except in full-program LTO. C++ function template instead follows the ODR | 
|  | rule that says that all definitions must be equivalent, making them | 
|  | inlineable. |