How to get code for a function template specialization

Hello there, thanks for your time reading this :slight_smile:

I am trying to extract the code for a specialized template function, but I have no idea on how to proceed. I know I can use SourceManager to get the original ‘pure template’ code but I don’t know how to access the specialized functions (the SourceLocation for them points to the original function in the AST). My idea is to allow users to write some sugar code like:

template
T myAdd(T x, T y) {
return x + y;

}

myAdd< double >(5.5, 3.3);
or

myAdd(1, 2);

and after parsing their source files, generate the specialized functions with a different name in a separated utility file, replacing the occurrences of of use (that’s the easy part).

The utility file would look like:

double _impl_double_myAdd(double x, double y) {
return x + y;
}

int _impl_int_myAdd(int x, int y) {
return x + y;
}

and the calls:

_impl_double_myAdd(5.5, 3.3);
and
_impl_int_myAdd(1, 2);

Can anyone point me in the right direction? I though about just replacing the usage cases of ‘T’ but that seems really manual and error prone.
Thanks!

You can call clang::Decl::print on the template specialization declaration to see what it looks like after substitution. We don’t guarantee that the output will be valid C++ code in all cases (and in fact, there are some constructs that can be produced by template instantiation and cannot be written directly in C++, but they’re generally very rare), but it usually will be.

If you want a sample of what that looks like, try compiling your code with “-Xclang -ast-print -S -o -”

For your original example (with the calls to myAdd moved to a function f()), I get this with clang trunk:

template T myAdd(T x, T y) {
return x + y;
}
template<> double myAdd(double x, double y) {
return x + y;
}
template<> int myAdd(int x, int y) {
return x + y;
}
void f() {
myAdd(5.5, 3.2999999999999998);
myAdd(1, 2);
}

Example case where the output is not valid C++:

template
void destroy(T &t) { t.~T(); }
void f(int n) { destroy(n); }

… produces …

template void destroy(T &t) {
t.~T();
}
template<> void destroy(int &t) {
t.~int(); // this won’t parse
}
void f(int n) {
destroy(n);
}

Thanks, this solved my problem!

Now I’m facing a second problem. I am able to generate the template function bodies using print, but I can’t seem to be able to locate the CallExpr inside the printed bodies (the spelling locations point to the non specialized template). I need this because I might have a template function calling another function, and I need to write both of them (and replace their calling names).

Example:

template < typename T >
T add(T x, T y) {
return x + y;

}

template < typename T >
T mul(T x, T y) {
return x * y;

}

template < typename T >
T test(T a, T x, T b) {
return add(mul(a,x), b);

}

int main() {
std::cout << test(2, 3, 4) << std::endl;

}