D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 9748 - Wrong scope of templated nested functions in static foreach
Summary: Wrong scope of templated nested functions in static foreach
Status: RESOLVED DUPLICATE of issue 14831
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P2 normal
Assignee: No Owner
URL:
Keywords: wrong-code
: 9756 (view as issue list)
Depends on:
Blocks:
 
Reported: 2013-03-18 08:01 UTC by Vladimir Panteleev
Modified: 2015-07-27 13:16 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 Vladimir Panteleev 2013-03-18 08:01:51 UTC
template Tuple(T...) { alias T Tuple; }

void main()
{
	foreach (i; Tuple!(1, 2, 3))
	{
		uint j;
		void set()(int n) { j = n; }
		set(i);
		assert(j==i);
	}
}

This fails because the "set" function will always refer to the "j" variable declared in the first foreach iteration. If you move the "j" declaration outside the loop, the asserts pass.
Comment 1 Kenji Hara 2013-10-03 00:48:48 UTC
More explicit test case:

template Tuple(T...) { alias T Tuple; }
extern(C) int printf(const char*, ...);
void main()
{
    //foreach (i; Tuple!(1, 2))
    {
        enum i = 1;
        uint j;
        void set()(int n) { j = n; printf("set1\n"); }
        set(i);
        printf("i = %d, j = %d\n", i, j);
        assert(j == i);
    }
    //foreach (i; Tuple!(1, 2))
    {
        enum i = 2;
        uint j;
        void set()(int n) { j = n; printf("set2\n"); }
        set(i);
        printf("i = %d, j = %d\n", i, j);
        assert(j == i);
    }
}

The second 'set' function template is not called.
Comment 2 Mathias LANG 2014-09-27 11:22:20 UTC
Real world use case where I hit this bug:

import std.typetuple, std.traits;

struct UDAStruct {
    string identifier;
}

class MyClass {
    @(UDAStruct("p3"), UDAStruct("P2"), UDAStruct("p1"))
      void func(int p1, string p2, float p3) {}
}

template CmpIdentifier(UDAStruct uda, string pname) {
    pragma(msg, "Instantiated for: "~pname);
    enum CmpIdentifier = (uda.identifier == pname);
}

unittest {
    alias Func = MyClass.func;
    enum ParamNames = ParameterIdentifierTuple!Func;
    enum ParamAttr = __traits(getAttributes, Func);

    foreach (attr; ParamAttr) {
        alias Cmp(string s) = CmpIdentifier!(attr, s);
        pragma(msg, "Current attr is: "~attr.identifier);
        static assert(anySatisfy!(Cmp, ParamNames));
    }
}

void main() {}


Output:
Current attr is: p3
Instantiated for: p1
Instantiated for: p2
Instantiated for: p3
Current attr is: P2
Current attr is: p1

(From: http://forum.dlang.org/thread/ojmpcrxrobjoqfrksjcv@forum.dlang.org )
Comment 3 Walter Bright 2014-10-16 18:45:53 UTC
Even smaller test case report from Mathias Lang:

void main()
{
    {
        void set()(int i) { assert(i); }
        set(1);
    }
    {
        void set()(int i) {}
        set(0);
    }
}

You probably know what's going to happen: the assert would be triggered. The FE would behave correctly, but backend will mangle the two functions the same way, leading to the first instance of "set" replacing the second one, and a nice linker message (Linux x86_64):
/usr/bin/ld: Warning: size of symbol `_D9a_bug97484mainFZ8__T3setZ3setMFNaNbNiNfiZv' changed from 29 in a_bug9748.o to 10 in a_bug9748.o
Comment 4 Mathias LANG 2014-10-16 19:22:56 UTC
Thank you Walter.
As mentioned in my email, solving this will require some change in the mangling scheme to support declarations in different nested scope.
In addition, if we allow this as valid code, we should relax the limitation exhibited by #4894 [1]. Would you agree to it ?
This needs support from the backend, as the mangling will change to take nested scope into account.

[1] https://issues.dlang.org/show_bug.cgi?id=4894
Possibly related bugs: https://issues.dlang.org/show_bug.cgi?id=10619
Comment 5 Kenji Hara 2015-07-26 13:19:59 UTC
*** Issue 9756 has been marked as a duplicate of this issue. ***
Comment 6 Kenji Hara 2015-07-27 13:16:34 UTC

*** This issue has been marked as a duplicate of issue 14831 ***