Add a `rs_name` field to `IncompleteRecord`
So far we used `cc_name` in the generated bindings, assuming that it will be a valid identifier on the `.rs` side. This is however not true for forward declared class template specializations.
PiperOrigin-RevId: 456578468
diff --git a/rs_bindings_from_cc/importers/cxx_record.cc b/rs_bindings_from_cc/importers/cxx_record.cc
index 8eccb6d..4ecad22 100644
--- a/rs_bindings_from_cc/importers/cxx_record.cc
+++ b/rs_bindings_from_cc/importers/cxx_record.cc
@@ -5,7 +5,6 @@
#include "rs_bindings_from_cc/importers/cxx_record.h"
#include "absl/strings/match.h"
-#include "absl/strings/substitute.h"
#include "rs_bindings_from_cc/ast_convert.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
@@ -112,6 +111,7 @@
ictx_.MarkAsSuccessfullyImported(record_decl);
return IncompleteRecord{
.cc_name = std::move(cc_name),
+ .rs_name = std::move(rs_name),
.id = GenerateItemId(record_decl),
.owning_target = ictx_.GetOwningTarget(record_decl),
// We generate top level bindings for implicit class template
diff --git a/rs_bindings_from_cc/ir.cc b/rs_bindings_from_cc/ir.cc
index 97f3f2e..bc8544d 100644
--- a/rs_bindings_from_cc/ir.cc
+++ b/rs_bindings_from_cc/ir.cc
@@ -362,6 +362,7 @@
llvm::json::Value IncompleteRecord::ToJson() const {
llvm::json::Object record{
{"cc_name", cc_name},
+ {"rs_name", rs_name},
{"id", id},
{"owning_target", owning_target},
};
diff --git a/rs_bindings_from_cc/ir.h b/rs_bindings_from_cc/ir.h
index a5ec007..777166a 100644
--- a/rs_bindings_from_cc/ir.h
+++ b/rs_bindings_from_cc/ir.h
@@ -613,6 +613,7 @@
struct IncompleteRecord {
llvm::json::Value ToJson() const;
std::string cc_name;
+ std::string rs_name;
ItemId id;
BazelLabel owning_target;
llvm::Optional<ItemId> enclosing_namespace_id;
diff --git a/rs_bindings_from_cc/ir.rs b/rs_bindings_from_cc/ir.rs
index cfc213b..b354bf6 100644
--- a/rs_bindings_from_cc/ir.rs
+++ b/rs_bindings_from_cc/ir.rs
@@ -373,6 +373,7 @@
#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
pub struct IncompleteRecord {
pub cc_name: String,
+ pub rs_name: String,
pub id: ItemId,
pub owning_target: BazelLabel,
pub enclosing_namespace_id: Option<ItemId>,
diff --git a/rs_bindings_from_cc/ir_from_cc_test.rs b/rs_bindings_from_cc/ir_from_cc_test.rs
index 3c0809c..5fc7c4d 100644
--- a/rs_bindings_from_cc/ir_from_cc_test.rs
+++ b/rs_bindings_from_cc/ir_from_cc_test.rs
@@ -3334,3 +3334,33 @@
}
);
}
+
+#[test]
+fn test_incomplete_record_has_rs_name() {
+ let ir = ir_from_cc(
+ r#"
+ namespace test_namespace_bindings {
+ template <typename T>
+ struct MyTemplate {
+ void processT(T t);
+ };
+
+ struct Param {};
+
+ template<> struct MyTemplate<Param>;
+ }"#,
+ )
+ .unwrap();
+
+ assert_ir_matches!(
+ ir,
+ quote! {
+ ...
+ IncompleteRecord {
+ cc_name: "test_namespace_bindings::MyTemplate<test_namespace_bindings::Param>",
+ rs_name: "__CcTemplateInstN23test_namespace_bindings10MyTemplateINS_5ParamEEE",
+ ...
+ } ...
+ }
+ );
+}
diff --git a/rs_bindings_from_cc/src_code_gen.rs b/rs_bindings_from_cc/src_code_gen.rs
index 7cda76d..d4dee7f 100644
--- a/rs_bindings_from_cc/src_code_gen.rs
+++ b/rs_bindings_from_cc/src_code_gen.rs
@@ -992,8 +992,8 @@
/// Generates Rust source code for a given incomplete record declaration.
fn generate_incomplete_record(incomplete_record: &IncompleteRecord) -> Result<TokenStream> {
- let ident = make_rs_ident(&incomplete_record.cc_name);
- let name = &incomplete_record.cc_name;
+ let ident = make_rs_ident(&incomplete_record.rs_name);
+ let name = &incomplete_record.rs_name;
Ok(quote! {
forward_declare::forward_declare!(
pub #ident __SPACE__ = __SPACE__ forward_declare::symbol!(#name)
@@ -2181,7 +2181,7 @@
namespace_qualifier,
crate_ident,
} => {
- let record_ident = make_rs_ident(&incomplete_record.cc_name);
+ let record_ident = make_rs_ident(&incomplete_record.rs_name);
let namespace_idents = namespace_qualifier.iter();
match crate_ident {
Some(ci) => {
@@ -6106,4 +6106,36 @@
);
Ok(())
}
+
+ #[test]
+ fn test_forward_declared_class_template_specialization_symbol() -> Result<()> {
+ let rs_api = generate_bindings_tokens(&ir_from_cc(
+ r#"
+ namespace test_namespace_bindings {
+ template <typename T>
+ struct MyTemplate {
+ void processT(T t);
+ };
+
+ struct Param {};
+
+ template<> struct MyTemplate<Param>;
+ }"#,
+ )?)?
+ .rs_api;
+
+ assert_rs_matches!(
+ rs_api,
+ quote! {
+ ...
+ pub mod test_namespace_bindings {
+ ...
+ forward_declare::forward_declare!(pub __CcTemplateInstN23test_namespace_bindings10MyTemplateINS_5ParamEEE = forward_declare::symbol!("__CcTemplateInstN23test_namespace_bindings10MyTemplateINS_5ParamEEE"));
+ ...
+ }
+ ...
+ }
+ );
+ Ok(())
+ }
}
diff --git a/rs_bindings_from_cc/test/golden/templates.h b/rs_bindings_from_cc/test/golden/templates.h
index e3eb416..0e6c0a9 100644
--- a/rs_bindings_from_cc/test/golden/templates.h
+++ b/rs_bindings_from_cc/test/golden/templates.h
@@ -54,4 +54,9 @@
using TopLevelTemplateWithNonTopLevelParam =
MyTopLevelTemplate<test_namespace_bindings::TemplateParam>;
+template <>
+struct MyTopLevelTemplate<int>;
+
+void processForwardDeclaredSpecialization(MyTopLevelTemplate<int>* i);
+
#endif // THIRD_PARTY_CRUBIT_RS_BINDINGS_FROM_CC_TEST_GOLDEN_TEMPLATES_H_
diff --git a/rs_bindings_from_cc/test/golden/templates_rs_api.rs b/rs_bindings_from_cc/test/golden/templates_rs_api.rs
index 6a5068d..37825d7 100644
--- a/rs_bindings_from_cc/test/golden/templates_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/templates_rs_api.rs
@@ -268,6 +268,17 @@
pub type TopLevelTemplateWithNonTopLevelParam =
crate::__CcTemplateInst18MyTopLevelTemplateIN23test_namespace_bindings13TemplateParamEE;
+forward_declare::forward_declare!(pub __CcTemplateInst18MyTopLevelTemplateIiE = forward_declare::symbol!("__CcTemplateInst18MyTopLevelTemplateIiE"));
+
+#[inline(always)]
+pub fn processForwardDeclaredSpecialization<'a>(
+ i: Option<crate::rust_std::pin::Pin<&'a mut crate::__CcTemplateInst18MyTopLevelTemplateIiE>>,
+) {
+ unsafe {
+ crate::detail::__rust_thunk___Z36processForwardDeclaredSpecializationP18MyTopLevelTemplateIiE(i)
+ }
+}
+
// THIRD_PARTY_CRUBIT_RS_BINDINGS_FROM_CC_TEST_GOLDEN_TEMPLATES_H_
#[ctor::recursively_pinned]
@@ -1266,6 +1277,14 @@
>,
__param_0: ctor::RvalueReference<'b, crate::test_namespace_bindings::TemplateParam>,
) -> crate::rust_std::pin::Pin<&'a mut crate::test_namespace_bindings::TemplateParam>;
+ #[link_name = "_Z36processForwardDeclaredSpecializationP18MyTopLevelTemplateIiE"]
+ pub(crate) fn __rust_thunk___Z36processForwardDeclaredSpecializationP18MyTopLevelTemplateIiE<
+ 'a,
+ >(
+ i: Option<
+ crate::rust_std::pin::Pin<&'a mut crate::__CcTemplateInst18MyTopLevelTemplateIiE>,
+ >,
+ );
pub(crate) fn __rust_thunk___ZN23test_namespace_bindings10MyTemplateI14DifferentScopeEC1Ev__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc<
'a,
>(