[cfe-users] How to get code for a function template specialization

Romulo via cfe-users cfe-users at lists.llvm.org
Tue Aug 20 10:55:31 PDT 2019


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;
}

----------------------------------
What I wanted to print:
----------------------------------

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

int mul_int(int x, int y) {
  return x * y;
}

int test_int(int a, int x, int b) {
  return add_int(mul_int(a,x), b);
}

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

When generating the source for test, I can call clang again and recursively
expand each function but that's undesirable and probably slow. I could also
parse generated expressions, but that could lead to errors. And finally I
though about getting in the way of printing (and printing my own names on
CallExpr) or to modify the AST itself but I have no idea how to do that.

Thanks once again.




On Wed, Aug 7, 2019 at 5:58 PM Romulo <abra185 at gmail.com> wrote:

> Thanks, this solved my problem!
>
> On Sun, Aug 4, 2019 at 11:07 PM Richard Smith <richard at metafoo.co.uk>
> wrote:
>
>> On Fri, 2 Aug 2019 at 15:05, Romulo via cfe-users <
>> cfe-users at lists.llvm.org> wrote:
>>
>>> Hello there, thanks for your time reading this :)
>>>
>>> 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 <typename T>
>>> 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.
>>>
>>
>> You can call clang::Decl::print
>> <https://clang.llvm.org/doxygen/classclang_1_1Decl.html#a5bac5131c3f19c2f460c1437eedb051c>
>> 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 <typename T> T myAdd(T x, T y) {
>>     return x + y;
>> }
>> template<> double myAdd<double>(double x, double y) {
>>     return x + y;
>> }
>> template<> int myAdd<int>(int x, int y) {
>>     return x + y;
>> }
>> void f() {
>>     myAdd<double>(5.5, 3.2999999999999998);
>>     myAdd(1, 2);
>> }
>>
>> Example case where the output is not valid C++:
>>
>> template <typename T>
>> void destroy(T &t) { t.~T(); }
>> void f(int n) { destroy(n); }
>>
>> ... produces ...
>>
>> template <typename T> void destroy(T &t) {
>>     t.~T();
>> }
>> template<> void destroy<int>(int &t) {
>>     t.~int(); // this won't parse
>> }
>> void f(int n) {
>>     destroy(n);
>> }
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-users/attachments/20190820/fb95386d/attachment.html>


More information about the cfe-users mailing list