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`