4 days ago

Compiler Explorer: GDC 15.2 '-O2 -fno-moduleinfo'
Source:

int pass(int a) { return a; } //normal function

int add(int num) { return pass(num) + num;}

Output:

int example.pass(int):
        mov     eax, edi
        ret
int example.add(int):
        lea     eax, [rdi+rdi]
        ret

as expected. Now changing 'pass' to template function

int pass()(int a) { return a; } //template function

int add(int num) { return pass(num) + num;}

Output:

pure nothrow @nogc @safe int example.pass!().pass(int):
        mov     eax, edi
        ret
int example.add(int):
        push    rbx
        mov     ebx, edi
        call    pure nothrow @nogc @safe int example.pass!().pass(int)
        add     eax, ebx
        pop     rbx
        ret

way worst output.
Lets force inlining template function

pragma(inline,true)
int pass()(int a) { return a; } //template function (force inline)

int add(int num) { return pass(num) + num;}

Output:

int example.add(int):
        lea     eax, [rdi+rdi]
        ret

Now we get expected output.
But lack of inlining is not the only problem because

pragma(inline,false)
int pass(int a) { return a; } //normal function (no inline)

int add(int num) { return pass(num) + num;}

Output:

int example.pass(int):
        mov     eax, edi
        ret
int example.add(int):
        call    int example.pass(int)
        add     eax, edi
        ret

which is still better output than templated one.
I checked multiple version GDC on 'Compiler Explorer' and last version you get expected output for templated functions is GDC 10.5
My local GDC(15.2.1) installation give same result as 'Compiler Explorer' one.
Tested c++ equivalent code and got expected result

2 days ago

On Sunday, 5 October 2025 at 03:26:21 UTC, qxi wrote:

>

as expected. Now changing 'pass' to template function

int pass()(int a) { return a; } //template function

int add(int num) { return pass(num) + num;}

Output:

-- snip --

>

way worst output.

Tracked in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102765

DMD emits templates as weak symbols, that it chooses to inline such functions violates ODR.

There was a proposal to fix druntime that would allow reversing the behaviour change: https://github.com/dlang/druntime/pull/3716.

As it stands, one potential way forward would be to restrict weak linkage to just extern(C) declarations in templates. All other symbols then get thrown into the linkonce section.

>

Now we get expected output.
But lack of inlining is not the only problem because

pragma(inline,false)
int pass(int a) { return a; } //normal function (no inline)

int add(int num) { return pass(num) + num;}

Output:

--snip--

>

which is still better output than templated one.

These two code blocks are not equivalent. G++ and GDC produce the same code when the regular function is annotated correctly.

https://compiler-explorer.com/z/YqoG918GK