D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 6574 - Erroneous recursive call in template instantiation
Summary: Erroneous recursive call in template instantiation
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P2 critical
Assignee: No Owner
URL:
Keywords: pull, spec, wrong-code
Depends on:
Blocks:
 
Reported: 2011-08-29 19:49 UTC by Andrej Mitrovic
Modified: 2015-02-18 03:42 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Andrej Mitrovic 2011-08-29 19:49:09 UTC
For lack of a better name..

import std.stdio;

enum Method
{
    A,
    B,
}

void Foo(Method method = Method.A)()
{
    write("dispatch, ");
    Foo!method();
}

void Foo(Method method : Method.A)()
{
    writeln("Foo A");
}

void Foo(Method method : Method.B)()
{
    writeln("Foo B");
}

void main()
{
    Foo!();           // dispatch, Foo A
    Foo();            // dispatch, Foo A
}

That works. Now uncomment the first instantiation, the `Foo!()` part and compile and run. The "dispatch" template instance keeps calling itself until the stack is blown and the app exits.

What I was trying to do with code like the above was to use template overloading with type specialization to switch between different types of drawing methods. The default "dispatch" template is there in case the user doesn't care which drawing method to use, the dispatch would then instantiate a specialized template (one specialized for Method.A in this case).

But as you can see, this is buggy territory..
Comment 1 Infiltrator 2014-03-19 20:18:16 UTC
As of v2.065, the provided code compiles and runs without errors.  Taking out the 'Foo!();' line causes a compilation warning about a size change but still seems to compile and run fine (though there probably is a bug there).
Comment 2 Andrej Mitrovic 2014-03-20 01:11:38 UTC
(In reply to comment #1)
> As of v2.065, the provided code compiles and runs without errors.  Taking out
> the 'Foo!();' line causes a compilation warning about a size change but still
> seems to compile and run fine (though there probably is a bug there).

The following runs forever for me with 2.065:

-----
import std.stdio;

enum Method
{
    A,
    B,
}

void Foo(Method method = Method.A)()
{
    write("dispatch, ");
    Foo!method();
}

void Foo(Method method : Method.A)()
{
    writeln("Foo A");
}

void Foo(Method method : Method.B)()
{
    writeln("Foo B");
}

void main()
{
    Foo();            // dispatch, Foo A
}
-----

I can't see any compilation warnings either.
Comment 3 Infiltrator 2014-03-20 05:54:44 UTC
That's very odd.  For me, the infloop only happens with my v2.062 gdc; my v2.065 dmd and dpaste's v2.065 both give the warning and output of "dispatch, Foo A".
Comment 4 Kenji Hara 2015-01-09 10:13:44 UTC
This is a mangling scheme issue and function symbol is confused in link stage.

module test;
extern(C) int printf(const char*, ...);
enum Method { A, B, }

void foo(Method method = Method.A)()
{
    pragma(msg, "1: ", foo.mangleof);
    foo!method();
}
void foo(Method method : Method.A)()
{
    pragma(msg, "2: ", foo.mangleof);
}
void main()
{
    foo();
}

foo() instantiates the first version `void foo(Method method = Method.A)()`,
then it instantiates the second version `void foo(Method method : Method.A)()`.

But the instantiated two functions have exactly same mangled names, so the pragmas print:

1: _D4test24__T3fooVE4test6Methodi1Z3fooFZv
2: _D4test24__T3fooVE4test6Methodi1Z3fooFZv

and the foo!method() wrongly call itself.
Comment 6 github-bugzilla 2015-01-10 00:57:38 UTC
Commits pushed to master at https://github.com/D-Programming-Language/dmd

https://github.com/D-Programming-Language/dmd/commit/fe6d7d7134263dbda68711675ffce09283264c4c
fix Issue 6574 - Erroneous recursive call in template instantiation

https://github.com/D-Programming-Language/dmd/commit/51d514ce773fd237e8e4a091751a27e68d309184
Merge pull request #4270 from 9rnsr/fix6574

Issue 6574 - Erroneous recursive call in template instantiation
Comment 7 github-bugzilla 2015-01-10 00:57:54 UTC
Commits pushed to master at https://github.com/D-Programming-Language/dlang.org

https://github.com/D-Programming-Language/dlang.org/commit/cad8d0e8b8201f3ae303241fed62afbb086b7be7
fix Issue 6574 - Erroneous recursive call in template instantiation

Improve mangling scheme to distinguish instantiations with specialized template parameters.

If a template argument matches to specialized template parameter, the argument is mangled with prefix 'H'.

https://github.com/D-Programming-Language/dlang.org/commit/416e78085d70c964c29136fe2707b9efec4c1980
Merge pull request #750 from 9rnsr/fix6574

Issue 6574 - Erroneous recursive call in template instantiation
Comment 8 Walter Bright 2015-01-10 01:00:35 UTC
Not fully fixed until core.demangle is updated.
Comment 9 Kenji Hara 2015-01-10 03:20:10 UTC
(In reply to Walter Bright from comment #8)
> Not fully fixed until core.demangle is updated.

https://github.com/D-Programming-Language/druntime/pull/1093
Comment 11 Andrej Mitrovic 2015-01-10 07:01:00 UTC
Thanks Kenji, pretty cool fix there!
Comment 12 github-bugzilla 2015-02-18 03:42:15 UTC
Commits pushed to 2.067 at https://github.com/D-Programming-Language/dmd

https://github.com/D-Programming-Language/dmd/commit/fe6d7d7134263dbda68711675ffce09283264c4c
fix Issue 6574 - Erroneous recursive call in template instantiation

https://github.com/D-Programming-Language/dmd/commit/51d514ce773fd237e8e4a091751a27e68d309184
Merge pull request #4270 from 9rnsr/fix6574