Support `#[recursively_pinned]` generics.

This is mostly only important for its interaction with lifetimes. We don't expect to support generic types in C++ interop, not as Rust generics -- but we do expect, I think, to support C++ classes with lifetime parameters, which would become generic parameters.

I had put off implementing it because it introduces the possibility of name collision, but now is as good a time as any to implement it. (It will help fix up tests in one of the other CLs I'm working on.)

I'm actually really impressed by the thoroughness of `syn` here. Even if it doesn't automatically give me hygiene, it does have all the facilities I need. It looks ugly, but nonetheless I am impressed by e.g. https://docs.rs/syn/latest/syn/struct.Generics.html#method.split_for_impl .

---

P.S. I have *no idea* how to implement `add_lifetime()` in a nice, copy-free, readable way. I know how I'd do it in Python, but...

This CL contains my best attempt (using `Cow`). Alternate idea was to move the logic into a function, something like:

```rs
fn add_lifetime(generics: &mut syn::Generics, prefix: &str) -> proc_macro2::TokenStream {
    let taken_lifetimes: HashSet<&syn::Lifetime> = generics.lifetimes().map(|def| &def.lifetime).collect();
    let try_lifetime = |name: &str| -> Option<syn::Lifetime> {
        let lifetime = syn::Lifetime::new(name, Span::call_site());
        if taken_lifetimes.contains(&lifetime) { None } else { Some(lifetime) }
    };

    let lifetime = try_lifetime(prefix).unwrap_or_else(|| {
        (2..).map(|n| format!("{prefix}_{n}")).find_map(|s| try_lifetime(&s)).unwrap()
    });
    let quoted_lifetime = quote! {#lifetime};
    generics.params.push(syn::GenericParam::Lifetime(syn::LifetimeDef::new(lifetime)));
    quoted_lifetime
}
```

But this is repellant to me, tbh.

PiperOrigin-RevId: 454042762
2 files changed
tree: 267aa6e14eb966297f032d17b72e3f9acd10076b
  1. .bazelci/
  2. bazel/
  3. cc_template/
  4. common/
  5. docs/
  6. lifetime_analysis/
  7. lifetime_annotations/
  8. migrator/
  9. nullability_verification/
  10. rs_bindings_from_cc/
  11. .bazelrc
  12. .gitignore
  13. BUILD
  14. Cargo.Bazel.lock
  15. CODE_OF_CONDUCT
  16. CONTRIBUTING
  17. LICENSE
  18. README.md
  19. WORKSPACE
README.md

Crubit: C++/Rust Bidirectional Interop Tool

Build status

Extremely experimental interop tooling 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.

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