Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proof of concept: Template functions #2650

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

Danacus
Copy link

@Danacus Danacus commented Sep 27, 2023

Hi, I wanted to explore if bindgen could support template functions and methods if some explicit instantiations are given in the header file, as explained in #492 (implicit instantiations also work just fine, clang doesn't seem to make a large distinction anyway).

As I mentioned in this issue, I believe this is currently not possible due to a limitation of libclang, so I decided to patch libclang such that instantiations of a template function are visited (patch based on LLVM 16):

diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 15652c499345..51c846356df0 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -950,7 +950,16 @@ bool CursorVisitor::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
     return true;
 
   auto *FD = D->getTemplatedDecl();
-  return VisitAttributes(FD) || VisitFunctionDecl(FD);
+  if (VisitAttributes(FD))
+    return true;
+  if (VisitFunctionDecl(FD))
+    return true;
+
+  for (auto *Child : D->specializations())
+    if (Visit(MakeCXCursor(Child, TU)))
+      return true; 
+  
+  return false;
 }
 
 bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) {

With this patch, bindgen can support template functions with just 3 additional lines of code (e8efccb).

I then tried the same thing for template methods, which was a bit more difficult in bindgen, and this solution is very much a proof of concept, not final code to be merged.

Here is an example of this proof of concept:

C++ header:

template<class T> void foo(T t) { }

// Explicit instantiation
extern template void foo(int);

class Test {
public:
  template <typename T> int bar(T t);
};

// Explicit instantiation
extern template int Test::bar(float);

void test() {
  // Implicit instantiation
  foo('f');

  Test t;
  // Implicit instantiation
  t.bar(5);
}

Generated Rust bindings:

/* automatically generated by rust-bindgen 0.68.1 */

extern "C" {
    #[link_name = "\u{1}_Z3fooIiEvT_"]
    pub fn foo(t: ::std::os::raw::c_int);
}
extern "C" {
    #[link_name = "\u{1}_Z3fooIcEvT_"]
    pub fn foo1(t: ::std::os::raw::c_char);
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Test {
    pub _address: u8,
}
#[test]
fn bindgen_test_layout_Test() {
    assert_eq!(
        ::std::mem::size_of::<Test>(),
        1usize,
        concat!("Size of: ", stringify!(Test))
    );
    assert_eq!(
        ::std::mem::align_of::<Test>(),
        1usize,
        concat!("Alignment of ", stringify!(Test))
    );
}
extern "C" {
    #[link_name = "\u{1}_ZN4Test3barIfEEiT_"]
    pub fn Test_bar(this: *mut Test, t: f32) -> ::std::os::raw::c_int;
}
extern "C" {
    #[link_name = "\u{1}_ZN4Test3barIiEEiT_"]
    pub fn Test_bar1(
        this: *mut Test,
        t: ::std::os::raw::c_int,
    ) -> ::std::os::raw::c_int;
}
impl Test {
    #[inline]
    pub unsafe fn bar(&mut self, t: f32) -> ::std::os::raw::c_int {
        Test_bar(self, t)
    }
    #[inline]
    pub unsafe fn bar1(
        &mut self,
        t: ::std::os::raw::c_int,
    ) -> ::std::os::raw::c_int {
        Test_bar1(self, t)
    }
}
extern "C" {
    #[link_name = "\u{1}_Z4testv"]
    pub fn test();
}

Would it be useful/interesting/worthwhile to open a PR on the LLVM repository to propose these changes, such that support for template functions can be implemented in bindgen? Or is there anything I have overlooked that might make things more complicated than they appear to be at first glance?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant