Suppress bindings for template instantiation, if suppressed for the definition.
PiperOrigin-RevId: 524108610
diff --git a/rs_bindings_from_cc/BUILD b/rs_bindings_from_cc/BUILD
index e4a680b..8432679 100644
--- a/rs_bindings_from_cc/BUILD
+++ b/rs_bindings_from_cc/BUILD
@@ -133,6 +133,9 @@
name = "bazel_types",
srcs = ["bazel_types.cc"],
hdrs = ["bazel_types.h"],
+ visibility = [
+ ":__subpackages__",
+ ],
deps = [
"//common:string_type",
"@absl//absl/log:check",
diff --git a/rs_bindings_from_cc/importers/BUILD b/rs_bindings_from_cc/importers/BUILD
index 9aee5fa..66da70c 100644
--- a/rs_bindings_from_cc/importers/BUILD
+++ b/rs_bindings_from_cc/importers/BUILD
@@ -25,6 +25,7 @@
"@absl//absl/log:check",
"@absl//absl/log:die_if_null",
"//rs_bindings_from_cc:ast_convert",
+ "//rs_bindings_from_cc:bazel_types",
"//rs_bindings_from_cc:decl_importer",
"@llvm-project//clang:ast",
"@llvm-project//clang:basic",
diff --git a/rs_bindings_from_cc/importers/cxx_record.cc b/rs_bindings_from_cc/importers/cxx_record.cc
index 38d46ac..de72298 100644
--- a/rs_bindings_from_cc/importers/cxx_record.cc
+++ b/rs_bindings_from_cc/importers/cxx_record.cc
@@ -12,6 +12,7 @@
#include "absl/log/die_if_null.h"
#include "absl/log/log.h"
#include "rs_bindings_from_cc/ast_convert.h"
+#include "rs_bindings_from_cc/bazel_types.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
@@ -209,6 +210,7 @@
clang::SourceLocation source_loc;
std::optional<std::string> doc_comment;
bool is_explicit_class_template_instantiation_definition = false;
+ std::optional<BazelLabel> defining_target;
if (auto* specialization_decl =
clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
record_decl)) {
@@ -229,6 +231,20 @@
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.
+ if (auto instantiation_source =
+ specialization_decl->getInstantiatedFrom()) {
+ clang::NamedDecl* decl;
+ if (auto* template_decl =
+ instantiation_source.dyn_cast<clang::ClassTemplateDecl*>()) {
+ decl = template_decl;
+ } else {
+ decl = instantiation_source
+ .get<clang::ClassTemplatePartialSpecializationDecl*>();
+ }
+ defining_target = ictx_.GetOwningTarget(decl);
+ }
} else {
const clang::NamedDecl* named_decl = record_decl;
if (record_decl->getName().empty()) {
@@ -301,6 +317,7 @@
.mangled_cc_name = ictx_.GetMangledName(record_decl),
.id = GenerateItemId(record_decl),
.owning_target = ictx_.GetOwningTarget(record_decl),
+ .defining_target = std::move(defining_target),
.doc_comment = std::move(doc_comment),
.source_loc = ictx_.ConvertSourceLocation(source_loc),
.unambiguous_public_bases = GetUnambiguousPublicBases(*record_decl),
diff --git a/rs_bindings_from_cc/ir.cc b/rs_bindings_from_cc/ir.cc
index a2b13ae..6e631b4 100644
--- a/rs_bindings_from_cc/ir.cc
+++ b/rs_bindings_from_cc/ir.cc
@@ -423,6 +423,7 @@
{"mangled_cc_name", mangled_cc_name},
{"id", id},
{"owning_target", owning_target},
+ {"defining_target", defining_target},
{"doc_comment", doc_comment},
{"source_loc", source_loc},
{"unambiguous_public_bases", unambiguous_public_bases},
diff --git a/rs_bindings_from_cc/ir.h b/rs_bindings_from_cc/ir.h
index aabb3b2..8430b15 100644
--- a/rs_bindings_from_cc/ir.h
+++ b/rs_bindings_from_cc/ir.h
@@ -557,6 +557,7 @@
ItemId id;
BazelLabel owning_target;
+ std::optional<BazelLabel> defining_target;
std::optional<std::string> doc_comment;
std::string source_loc;
std::vector<BaseClass> unambiguous_public_bases;
diff --git a/rs_bindings_from_cc/ir.rs b/rs_bindings_from_cc/ir.rs
index bbea229..9fc5fce 100644
--- a/rs_bindings_from_cc/ir.rs
+++ b/rs_bindings_from_cc/ir.rs
@@ -523,6 +523,9 @@
pub mangled_cc_name: Rc<str>,
pub id: ItemId,
pub owning_target: BazelLabel,
+ /// The target containing the template definition, if this is a templated
+ /// record type.
+ pub defining_target: Option<BazelLabel>,
pub doc_comment: Option<Rc<str>>,
pub source_loc: Rc<str>,
pub unambiguous_public_bases: Vec<BaseClass>,
@@ -858,10 +861,13 @@
}
}
- /// Returns the target that this was defined in.
+ /// Returns the target that this was defined in, if it was defined somewhere
+ /// other than `owning_target()`.
pub fn defining_target(&self) -> Option<&BazelLabel> {
- // TODO(b/266727458): return the template target where applicable.
- self.owning_target()
+ match self {
+ Item::Record(record) => record.defining_target.as_ref(),
+ _ => None,
+ }
}
/// Returns the target that this should generate source code in.
diff --git a/rs_bindings_from_cc/ir_from_cc_test.rs b/rs_bindings_from_cc/ir_from_cc_test.rs
index ec2b346..650f33f 100644
--- a/rs_bindings_from_cc/ir_from_cc_test.rs
+++ b/rs_bindings_from_cc/ir_from_cc_test.rs
@@ -2358,27 +2358,28 @@
assert_ir_matches!(
ir,
quote! {
- Record {
- rs_name: "DerivedClass",
- cc_name: "DerivedClass",
- mangled_cc_name: "12DerivedClass",
- id: ItemId(...),
- owning_target: BazelLabel("//test:testing_target"),
- doc_comment: Some(...),
- source_loc: "Generated from: google3/ir_from_cc_virtual_header.h;l=15",
- unambiguous_public_bases: [],
- fields: [Field {
- identifier: Some("derived_field"), ...
- offset: 32, ...
- }], ...
- size: 8,
- original_cc_size: 8,
- alignment: 4,
- is_derived_class: true,
- override_alignment: true,
- ...
- }
- }
+ Record {
+ rs_name: "DerivedClass",
+ cc_name: "DerivedClass",
+ mangled_cc_name: "12DerivedClass",
+ id: ItemId(...),
+ owning_target: BazelLabel("//test:testing_target"),
+ defining_target: None,
+ doc_comment: Some(...),
+ source_loc: "Generated from: google3/ir_from_cc_virtual_header.h;l=15",
+ unambiguous_public_bases: [],
+ fields: [Field {
+ identifier: Some("derived_field"), ...
+ offset: 32, ...
+ }], ...
+ size: 8,
+ original_cc_size: 8,
+ alignment: 4,
+ is_derived_class: true,
+ override_alignment: true,
+ ...
+ }
+ }
);
// Verify that the NestedStruct is unsupported (this is mostly verification
// that the test input correctly sets up the test scenario; the real
diff --git a/rs_bindings_from_cc/src_code_gen.rs b/rs_bindings_from_cc/src_code_gen.rs
index 40abda4..87aa469 100644
--- a/rs_bindings_from_cc/src_code_gen.rs
+++ b/rs_bindings_from_cc/src_code_gen.rs
@@ -289,7 +289,7 @@
return false;
}
- // ## Returning structs be value.
+ // ## Returning structs by value.
//
// Returning a struct by value requires an explicit thunk, because
// `rs_bindings_from_cc` may not preserve the ABI of structs (e.g. when
@@ -2810,13 +2810,15 @@
#[must_use]
fn has_bindings(db: &dyn BindingsGenerator, item: &Item) -> HasBindings {
let ir = db.ir();
- if let Some(defining_target) = item.defining_target() {
- let missing_features =
- crubit_features_for_item(item) - ir.target_crubit_features(defining_target);
+ // We refuse to generate bindings if either the definition of an item, or
+ // instantiation (if it is a template) an item are in a translation unit which
+ // doesn't have the required Crubit features.
+ for target in item.defining_target().into_iter().chain(item.owning_target()) {
+ let missing_features = crubit_features_for_item(item) - ir.target_crubit_features(target);
if !missing_features.is_empty() {
return HasBindings::No(NoBindingsReason::MissingRequiredFeatures {
missing_features,
- target: defining_target.clone(),
+ target: target.clone(),
});
}
}
diff --git a/rs_bindings_from_cc/test/crubit_features/test.rs b/rs_bindings_from_cc/test/crubit_features/test.rs
index ce690f1..9690334 100644
--- a/rs_bindings_from_cc/test/crubit_features/test.rs
+++ b/rs_bindings_from_cc/test/crubit_features/test.rs
@@ -41,7 +41,6 @@
/// in other headers should respect the template _definition_ and its
/// API promises.
#[test]
- #[ignore] // TODO(b/266727458): implement this
fn aliases_dont_expose_disabled_templates() {
assert!(
!type_exists!(alias_enabled::AliasedDisabledTemplate),