Move bazel label suffix logic to Rust / `src_code_gen.rs`.

I also slightly tweaked the logic -- the bazel label suffix no longer crashes for empty bazel labels, or bazel labels that begin with a number. (Not that these ever exist!)

---

Background:

When a template class is instantiated, the function needs to have an added suffix, so that we do not generate multiple functions with the same symbol name. See [this doc](https://github.com/google/crubit/blob/main/docs/thunks_for_class_template_member_functions.md) for details.

The existing logic was fine and worked, but, it could not be invoked from Rust (needed for the linked bug) -- we need to use this mangled name when generating new C++ functions, not just for existing C++ functions.

Also, I will add, the existing logic was "action at a distance". It reused the `mangled_name` field, which normally refers to the actual symbol to link against, to add a suffix to it when it knows that we won't later try to link against it. So the code in file A was only correct due to code very far away in file B.

This code performed the addition of the suffix, in `importers/function.cc`:

```
  if (is_member_or_descendant_of_class_template) {
    // `thunks_for_class_template_member_functions.md` explains in more detail
    // why the `mangled_name` has to include the target name when working with
    // members or descendants of a class template.
    mangled_name += '_';
    mangled_name += ConvertToCcIdentifier(ictx_.GetOwningTarget(function_decl));
```

This would cause linking errors, since that mangled name now refers to a function that does not exist, except for this line of code in `src_code_gen.rs` (function `can_skip_cc_thunk`):

```
    if func.is_member_or_descendant_of_class_template {
        return false;
    }
```

Which causes (in a couple of different places) for a thunk to be generated, instead of linking to an existing thing with that `mangled_name`.

I would argue that this is fragile, or at least somewhat subtle/confusing. After this CL, since the logic is all in `src_code_gen.rs`, this goes away. We now _directly_ control the function name, entirely separately from the mangled name which is used for linking purposes. And so the suffix is added directly onto the thunk ident. Indeed, after this CL, we could use the suffix unconditionally for _all_ functions, if we so chose, removing the branch.

(And I would argue that we should indeed broaden the set of functions we add the suffix for. For example, if two headers define an (identical) inline function, e.g. due to textual headers with an inline function definition, the current code will cause an ODR violation, but an unconditional thunk rename would not. Being unconditional will just cause fewer bugs, I suspect. But, for now, this CL replicates the existing behavior closely.)

PiperOrigin-RevId: 584738431
Change-Id: I36820bca82ce58b47105416fb0256f6729db9ec2
10 files changed
tree: a0c8e57fffa4eabb41377daa17e2c9f2f0d2c920
  1. .bazelci/
  2. bazel/
  3. cc_bindings_from_rs/
  4. common/
  5. docs/
  6. examples/
  7. lifetime_analysis/
  8. lifetime_annotations/
  9. migrator/
  10. nullability/
  11. rs_bindings_from_cc/
  12. support/
  13. .bazelrc
  14. .gitignore
  15. BUILD
  16. Cargo.lock
  17. CODE_OF_CONDUCT
  18. CONTRIBUTING
  19. LICENSE
  20. README.md
  21. WORKSPACE
README.md

Crubit: C++/Rust Bidirectional Interop Tool

Build status

Crubit is an experimental bidirectional bindings generator for C++ and Rust.

Please don‘t use, this is an experiment and we don’t yet know where will it take us. There will be breaking changes without warning. Unfortunately, we can't take contributions at this point.

Crubit allows for C++ code and Rust code to call each other without manually wrapping the APIs in an FFI-friendly interop layer. For example, a C++ function like this:

bool IsAbsPath(std::string_view path);

... becomes callable from Rust as if it were defined as:

pub fn IsAbsPath(path: std::string_view) -> bool {...}

Crubit automatically generates ABI-compatible bindings for structs (which can be passed both by value and by reference), functions, and methods, for a large variety of types. (Trivial types, nontrivial types, templated types, etc.)

Building Crubit

$ apt install clang lld bazel
$ git clone git@github.com:google/crubit.git
$ cd crubit
$ bazel build --linkopt=-fuse-ld=/usr/bin/ld.lld //rs_bindings_from_cc:rs_bindings_from_cc_impl

Using a prebuilt LLVM tree

$ git clone https://github.com/llvm/llvm-project
$ cd llvm-project
$ CC=clang CXX=clang++ cmake -S llvm -B build -DLLVM_ENABLE_PROJECTS='clang' -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=install
$ cmake --build build -j
$ # wait...
$ cmake --install build
$ cd ../crubit
$ LLVM_INSTALL_PATH=../llvm-project/install bazel build //rs_bindings_from_cc:rs_bindings_from_cc_impl