Import decls in LinkageSpecDecl
We don't need an explicit Item for this decl, so in this CL we're changing
importer.cc to iterate decls inside LinkageSpecDecl right away.
PiperOrigin-RevId: 450869812
diff --git a/rs_bindings_from_cc/BUILD b/rs_bindings_from_cc/BUILD
index 2c373f0..0e1be69 100644
--- a/rs_bindings_from_cc/BUILD
+++ b/rs_bindings_from_cc/BUILD
@@ -335,6 +335,7 @@
"//common:rust_allocator_shims",
"@crate_index//:anyhow",
"@crate_index//:itertools",
+ "@crate_index//:proc-macro2",
"@crate_index//:quote",
],
)
diff --git a/rs_bindings_from_cc/importer.cc b/rs_bindings_from_cc/importer.cc
index 4fdd514..b785291 100644
--- a/rs_bindings_from_cc/importer.cc
+++ b/rs_bindings_from_cc/importer.cc
@@ -298,10 +298,21 @@
}
absl::flat_hash_set<ItemId> visited_item_ids;
- for (auto child : decl_context->decls()) {
+ std::vector<clang::Decl*> decls_to_visit;
+ llvm::copy(decl_context->decls(), std::back_inserter(decls_to_visit));
+
+ while (!decls_to_visit.empty()) {
+ clang::Decl* child = decls_to_visit.back();
+ decls_to_visit.pop_back();
auto decl = child->getCanonicalDecl();
if (!IsFromCurrentTarget(decl)) continue;
+ if (const auto* linkage_spec_decl =
+ llvm::dyn_cast<clang::LinkageSpecDecl>(decl)) {
+ absl::c_copy(linkage_spec_decl->decls(),
+ std::back_inserter(decls_to_visit));
+ }
+
// We remove comments attached to a child decl or that are within a child
// decl.
if (auto raw_comment = ctx_.getRawCommentForDeclNoCache(decl)) {
@@ -413,9 +424,14 @@
void Importer::ImportDeclsFromDeclContext(
const clang::DeclContext* decl_context) {
for (auto decl : decl_context->decls()) {
- // TODO(rosica): We don't always want the canonical decl here (especially
- // not in namespaces).
- GetDeclItem(decl->getCanonicalDecl());
+ if (const auto* linkage_spec_decl =
+ llvm::dyn_cast<clang::LinkageSpecDecl>(decl)) {
+ ImportDeclsFromDeclContext(linkage_spec_decl);
+ } else {
+ // TODO(rosica): We don't always want the canonical decl here (especially
+ // not in namespaces).
+ GetDeclItem(decl->getCanonicalDecl());
+ }
}
}
diff --git a/rs_bindings_from_cc/ir_from_cc_test.rs b/rs_bindings_from_cc/ir_from_cc_test.rs
index 375e2f5..46eafca 100644
--- a/rs_bindings_from_cc/ir_from_cc_test.rs
+++ b/rs_bindings_from_cc/ir_from_cc_test.rs
@@ -2856,3 +2856,44 @@
// assert_eq!(namespaces[0].canonical_namespace_id,
// namespaces[1].canonical_namespace_id);
}
+
+#[test]
+fn test_items_inside_linkage_spec_decl_are_imported() {
+ let ir = ir_from_cc(
+ r#"
+ extern "C" {
+ struct MyStruct {};
+ }
+ "#,
+ )
+ .unwrap();
+ assert_ir_matches!(ir, quote! { Record { ... cc_name: "MyStruct" ... } })
+}
+
+#[test]
+fn test_items_inside_linkage_spec_decl_are_considered_toplevel() {
+ // The test below assumes the first top_level_item_ids element is the one added
+ // by the the source code under test. Let's double check that assumption here.
+ assert!(ir_from_cc("").unwrap().top_level_item_ids().next().is_none());
+
+ let ir = ir_from_cc(
+ r#"
+ extern "C" {
+ struct MyStruct {};
+ }"#,
+ )
+ .unwrap();
+ let item_id = proc_macro2::Literal::usize_unsuffixed(ir.top_level_item_ids().next().unwrap().0);
+
+ assert_ir_matches!(
+ ir,
+ quote! {
+ ...
+ Record {
+ ... cc_name: "MyStruct" ...
+ ... id: ItemId(#item_id) ...
+ }
+ ...
+ }
+ );
+}