Set `defining_target` for explicit template specializations.
There was an inconsistency here: while it's true that, in principle, since there's only one target involved here (the template specialization is defined in the target that owns it), the existence or nonexistence of `defining_target` is used elsewhere to determine whether a type is a template type. So we still need to populate the `defining_target` field, in order to e.g. filter it out correctly in `:supported` targets.
PiperOrigin-RevId: 684974881
Change-Id: I8bad2f6179d9cd36d7c4b0a57fa41e13512f8f84
diff --git a/rs_bindings_from_cc/generate_bindings/lib.rs b/rs_bindings_from_cc/generate_bindings/lib.rs
index ae77a19..46b63bd 100644
--- a/rs_bindings_from_cc/generate_bindings/lib.rs
+++ b/rs_bindings_from_cc/generate_bindings/lib.rs
@@ -3277,6 +3277,31 @@
}
#[gtest]
+ fn test_default_crubit_features_disabled_template_explicit_specialization() -> Result<()> {
+ let mut ir = ir_from_cc(
+ r#"
+ template <typename T>
+ struct X {
+ T t;
+ };
+
+ template <>
+ struct X<int> {
+ int val;
+ X<int>() : val(42) {}
+ };
+
+ inline X<int> NotPresent() { return X<int>(); }"#,
+ )?;
+ *ir.target_crubit_features_mut(&ir.current_target().clone()) =
+ crubit_feature::CrubitFeature::Supported.into();
+ let BindingsTokens { rs_api, rs_api_impl } = generate_bindings_tokens(ir)?;
+ assert_rs_not_matches!(rs_api, quote! {NotPresent});
+ assert_cc_not_matches!(rs_api_impl, quote! {NotPresent});
+ Ok(())
+ }
+
+ #[gtest]
fn test_type_map_override_assert() -> Result<()> {
let rs_api = generate_bindings_tokens(ir_from_cc(
r#" #pragma clang lifetime_elision
diff --git a/rs_bindings_from_cc/importers/cxx_record.cc b/rs_bindings_from_cc/importers/cxx_record.cc
index 0c382ee..436e74b 100644
--- a/rs_bindings_from_cc/importers/cxx_record.cc
+++ b/rs_bindings_from_cc/importers/cxx_record.cc
@@ -301,10 +301,9 @@
ictx_.GetComment(specialization_decl->getSpecializedTemplate());
}
source_loc = specialization_decl->getBeginLoc();
- /// Note: only specify defining_target if it's a template instantiation!
- /// Explicit specializations are their own defining_target.
+ // Specify defining_target if it's a template instantiation.
if (auto instantiation_source =
- specialization_decl->getInstantiatedFrom()) {
+ specialization_decl->getSpecializedTemplateOrPartial()) {
clang::NamedDecl* decl;
if (auto* template_decl =
instantiation_source.dyn_cast<clang::ClassTemplateDecl*>()) {
diff --git a/rs_bindings_from_cc/ir_from_cc_test.rs b/rs_bindings_from_cc/ir_from_cc_test.rs
index 56e109f..c9bb2a9 100644
--- a/rs_bindings_from_cc/ir_from_cc_test.rs
+++ b/rs_bindings_from_cc/ir_from_cc_test.rs
@@ -1284,7 +1284,8 @@
Record {
rs_name: "__CcTemplateInstN23test_namespace_bindings8MyStructIiEE", ...
cc_name: "test_namespace_bindings::MyStruct<int>", ...
- owning_target: BazelLabel("//test:testing_target"), ...
+ owning_target: BazelLabel("//test:testing_target"),
+ defining_target: Some(BazelLabel("//test:testing_target")), ...
doc_comment: Some("Doc comment for template specialization for T=int."), ...
fields: [Field {
identifier: Some("value"), ...
diff --git a/rs_bindings_from_cc/test/templates/explicit_specialization/BUILD b/rs_bindings_from_cc/test/templates/explicit_specialization/BUILD
new file mode 100644
index 0000000..4dc5f70
--- /dev/null
+++ b/rs_bindings_from_cc/test/templates/explicit_specialization/BUILD
@@ -0,0 +1,22 @@
+"""End-to-end example of explicit template specialization working."""
+
+load("//common:crubit_wrapper_macros_oss.bzl", "crubit_rust_test")
+load("//rs_bindings_from_cc/test:test_bindings.bzl", "crubit_test_cc_library")
+
+package(default_applicable_licenses = ["//:license"])
+
+crubit_test_cc_library(
+ name = "explicit_specialization",
+ hdrs = ["explicit_specialization.h"],
+)
+
+crubit_rust_test(
+ name = "main",
+ srcs = ["test.rs"],
+ cc_deps = [
+ ":explicit_specialization",
+ ],
+ deps = [
+ "@crate_index//:googletest",
+ ],
+)
diff --git a/rs_bindings_from_cc/test/templates/explicit_specialization/explicit_specialization.h b/rs_bindings_from_cc/test/templates/explicit_specialization/explicit_specialization.h
new file mode 100644
index 0000000..d9d9aed
--- /dev/null
+++ b/rs_bindings_from_cc/test/templates/explicit_specialization/explicit_specialization.h
@@ -0,0 +1,21 @@
+// 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
+
+#ifndef THIRD_PARTY_CRUBIT_RS_BINDINGS_FROM_CC_TEST_TEMPLATES_EXPLICIT_SPECIALIZATION_EXPLICIT_SPECIALIZATION_H_
+#define THIRD_PARTY_CRUBIT_RS_BINDINGS_FROM_CC_TEST_TEMPLATES_EXPLICIT_SPECIALIZATION_EXPLICIT_SPECIALIZATION_H_
+
+template <typename T>
+struct X {
+ T t;
+};
+
+template <>
+struct X<int> {
+ int val;
+ X<int>() : val(42) {}
+};
+
+inline X<int> ReturnX() { return X<int>(); }
+
+#endif // THIRD_PARTY_CRUBIT_RS_BINDINGS_FROM_CC_TEST_TEMPLATES_EXPLICIT_SPECIALIZATION_EXPLICIT_SPECIALIZATION_H_
diff --git a/rs_bindings_from_cc/test/templates/explicit_specialization/test.rs b/rs_bindings_from_cc/test/templates/explicit_specialization/test.rs
new file mode 100644
index 0000000..da09c57
--- /dev/null
+++ b/rs_bindings_from_cc/test/templates/explicit_specialization/test.rs
@@ -0,0 +1,15 @@
+// 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
+
+#[cfg(test)]
+mod tests {
+ use explicit_specialization::*;
+ use googletest::prelude::*;
+
+ #[gtest]
+ fn test_explicit_specialization_works_correctly() {
+ let x = ReturnX();
+ assert_eq!(42, x.val);
+ }
+}