Skip to content

Proof of concept: Template functions#2650

Draft
Danacus wants to merge 3 commits intorust-lang:mainfrom
Danacus:template-functions
Draft

Proof of concept: Template functions#2650
Danacus wants to merge 3 commits intorust-lang:mainfrom
Danacus:template-functions

Conversation

@Danacus
Copy link
Copy Markdown

@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?

@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented May 4, 2026

☔ The latest upstream changes (possibly #3365) made this pull request unmergeable. Please resolve the merge conflicts.

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.

2 participants