Support `cpp_name` annotation for struct/enum. PiperOrigin-RevId: 659351942 Change-Id: Ida7b662388e243489f98512ed882d60152b91ffd
diff --git a/bazel/llvm.bzl b/bazel/llvm.bzl index 99d30d8..30dcde5 100644 --- a/bazel/llvm.bzl +++ b/bazel/llvm.bzl
@@ -53,7 +53,7 @@ executable = False, ) -LLVM_COMMIT_SHA = "90617e99bb17303b351351681a70394c312e0e58" +LLVM_COMMIT_SHA = "a0a9bf5152507beacd2a72dda42d054391494c4a" def llvm_loader_repository_dependencies(): # This *declares* the dependency, but it won't actually be *downloaded* unless it's used.
diff --git a/cc_bindings_from_rs/bindings.rs b/cc_bindings_from_rs/bindings.rs index f7c0d46..d0f0eb3 100644 --- a/cc_bindings_from_rs/bindings.rs +++ b/cc_bindings_from_rs/bindings.rs
@@ -279,6 +279,16 @@ /// For example, if a type has `#[__crubit::annotate(cpp_type="x::y")]`, /// then cpp_type will be `Some(x::y)`. cpp_type: Option<Symbol>, + + /// The C++ name to use for the symbol. + /// + /// For example, the following struct + /// ``` + /// #[__crubit::annotate(cpp_name="Bar")] + /// struct Foo { ... } + /// ``` + /// will be generated as a C++ struct named `Bar` instead of `Foo`. + cpp_name: Option<Symbol>, } impl FullyQualifiedName { @@ -291,11 +301,13 @@ // Crash OK: these attributes are introduced by crubit itself, and "should // never" be malformed. - let cpp_type = crubit_attr::get(tcx, def_id).unwrap().cpp_type; + let attributes = crubit_attr::get(tcx, def_id).unwrap(); + let cpp_type = attributes.cpp_type; let mut full_path = tcx.def_path(def_id).data; // mod_path + name let name = full_path.pop().expect("At least the item's name should be present"); let name = name.data.get_opt_name(); + let cpp_name = attributes.cpp_name.map(|s| Symbol::intern(s.as_str())).or(name); let mod_path = NamespaceQualifier::new( full_path @@ -304,7 +316,7 @@ .map(|s| Rc::<str>::from(s.as_str())), ); - Self { krate, mod_path, name, cpp_type } + Self { krate, mod_path, name, cpp_type, cpp_name } } fn format_for_cc(&self) -> Result<TokenStream> { @@ -313,8 +325,9 @@ return Ok(quote! {#path}); } - let name = - self.name.as_ref().expect("`format_for_cc` can't be called on name-less item kinds"); + let name = self.cpp_name.as_ref().unwrap_or_else(|| { + self.name.as_ref().expect("`format_for_cc` can't be called on name-less item kinds") + }); let top_level_ns = format_cc_ident(self.krate.as_str())?; let ns_path = self.mod_path.format_for_cc()?; @@ -1383,7 +1396,7 @@ let struct_name = match struct_name.as_ref() { None => quote! {}, Some(fully_qualified_name) => { - let name = fully_qualified_name.name.expect("Structs always have a name"); + let name = fully_qualified_name.cpp_name.expect("Structs always have a name"); let name = format_cc_ident(name.as_str()) .expect("Caller of format_fn should verify struct via format_adt_core"); quote! { #name :: } @@ -1580,7 +1593,9 @@ assert!(self_ty.is_adt()); assert!(is_directly_public(tcx, def_id), "Caller should verify"); - let item_name = tcx.item_name(def_id); + let attribute = crubit_attr::get(tcx, def_id).unwrap(); + + let item_name = attribute.cpp_name.unwrap_or_else(|| tcx.item_name(def_id)); let rs_fully_qualified_name = format_ty_for_rs(tcx, self_ty)?; let cc_short_name = format_cc_ident(item_name.as_str()).context("Error formatting item name")?; @@ -3858,6 +3873,41 @@ }); } + #[test] + fn test_format_struct_cpp_name() { + let test_src = r#" + #![feature(register_tool)] + #![register_tool(__crubit)] + + #[__crubit::annotate(cpp_name="Bar")] + pub struct Foo { + pub x: i32, + } + "#; + test_format_item(test_src, "Foo", |result| { + let result = result.unwrap().unwrap(); + let main_api = &result.main_api; + assert!(!main_api.prereqs.is_empty()); + + assert_rs_matches!( + result.rs_details, + quote! { + const _: () = assert!(::std::mem::size_of::<::rust_out::Foo>() == 4); + const _: () = assert!(::std::mem::align_of::<::rust_out::Foo>() == 4); + const _: () = assert!(::core::mem::offset_of!(::rust_out::Foo, x) == 0); + } + ); + + assert_cc_matches!( + main_api.tokens, + quote! { + struct CRUBIT_INTERNAL_RUST_TYPE(":: rust_out :: Foo") alignas(4) + [[clang::trivial_abi]] Bar final + } + ); + }); + } + /// `test_format_item_fn_const` tests how bindings for an `const fn` are /// generated. ///
diff --git a/cc_bindings_from_rs/test/attribute/BUILD b/cc_bindings_from_rs/test/attribute/BUILD new file mode 100644 index 0000000..665d6d0 --- /dev/null +++ b/cc_bindings_from_rs/test/attribute/BUILD
@@ -0,0 +1,33 @@ +"""End-to-end tests of `cc_bindings_from_rs`, focusing on union-related +bindings.""" + +load( + "@rules_rust//rust:defs.bzl", + "rust_library", +) +load( + "//cc_bindings_from_rs/bazel_support:cc_bindings_from_rust_rule.bzl", + "cc_bindings_from_rust", +) +load("//common:crubit_wrapper_macros_oss.bzl", "crubit_cc_test") + +package(default_applicable_licenses = ["//:license"]) + +rust_library( + name = "cpp_name", + srcs = ["cpp_name.rs"], +) + +cc_bindings_from_rust( + name = "cpp_name_cc_api", + crate = ":cpp_name", +) + +crubit_cc_test( + name = "cpp_name_test", + srcs = ["cpp_name_test.cc"], + deps = [ + ":cpp_name_cc_api", + "@com_google_googletest//:gtest_main", + ], +)
diff --git a/cc_bindings_from_rs/test/attribute/cpp_name.rs b/cc_bindings_from_rs/test/attribute/cpp_name.rs new file mode 100644 index 0000000..6952c4d --- /dev/null +++ b/cc_bindings_from_rs/test/attribute/cpp_name.rs
@@ -0,0 +1,17 @@ +// Part of the Crubit project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#![feature(register_tool)] +#![register_tool(__crubit)] + +#[__crubit::annotate(cpp_name = "Replaced")] +pub struct Original { + pub x: i32, +} + +impl Original { + pub fn create() -> Self { + Self { x: 42 } + } +}
diff --git a/cc_bindings_from_rs/test/attribute/cpp_name_test.cc b/cc_bindings_from_rs/test/attribute/cpp_name_test.cc new file mode 100644 index 0000000..1b57618 --- /dev/null +++ b/cc_bindings_from_rs/test/attribute/cpp_name_test.cc
@@ -0,0 +1,20 @@ +// Part of the Crubit project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include <type_traits> +#include <utility> + +#include "gtest/gtest.h" +#include "cc_bindings_from_rs/test/attribute/cpp_name_cc_api.h" + +namespace crubit { +namespace { + +TEST(CppNameTest, RenameStruct) { + cpp_name::Replaced replaced = cpp_name::Replaced::create(); + EXPECT_EQ(replaced.x, 42); +} + +} // namespace +} // namespace crubit \ No newline at end of file
diff --git a/docs/rust/fine_tuning_bindings.md b/docs/rust/fine_tuning_bindings.md index 36a072d..383e461 100644 --- a/docs/rust/fine_tuning_bindings.md +++ b/docs/rust/fine_tuning_bindings.md
@@ -28,7 +28,7 @@ std::int32_t Create(); // named `Create` instead of `new`. ``` -Currently this attribute works on functions only (See b/349070421). +Currently this attribute works on functions and structs (See b/349070421). ## `cpp_type`