import core.stdc.stdio; struct S { int a,b,c,d; } alias int delegate() dg_t; alias int delegate(int) dg1_t; void fill() { int[100] x; } /************************************/ dg_t foo() { int x = 7; int bar() { return x + 3; } return &bar; } void test1() { dg_t dg = foo(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo2() { dg_t abc() { int x = 7; int bar() { return x + 3; } return &bar; } return abc(); } void test2() { dg_t dg = foo2(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo3() { dg_t abc(int x) { int bar() { return x + 3; } return &bar; } return abc(7); } void test3() { dg_t dg = foo3(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo4() { S s; s = S(4,5,6,7); dg_t abc(S t) { int bar() { return t.d + 3; } return &bar; } return abc(s); } void test4() { dg_t dg = foo4(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ void test5() { int x = 7; dg_t abc(ref int y) { int bar() { y += 4; return y + 3; } return &bar; } dg_t dg = abc(x); fill(); assert(x == 7); auto i = dg(); assert(x == 11); assert(i == 14); x = 8; i = dg(); assert(x == 12); assert(i == 15); } /************************************/ void test6() { int x = 7; dg_t abc(out int y) { int bar() { y += 4; return y + 3; } return &bar; } dg_t dg = abc(x); fill(); assert(x == 0); auto i = dg(); assert(x == 4); assert(i == 7); x = 8; i = dg(); assert(x == 12); assert(i == 15); } /************************************/ void test7() { int[3] a = [10,11,12]; dg_t abc(int[3] y) { int bar() { y[2] += 4; return y[2] + 3; } return &bar; } dg_t dg = abc(a); fill(); assert(a[2] == 12); auto i = dg(); assert(a[2] == 12); assert(i == 19); } /************************************/ void test8() { S s = S(7,8,9,10); dg_t abc(ref S t) { int bar() { t.d += 4; return t.c + 3; } return &bar; } dg_t dg = abc(s); fill(); assert(s.d == 10); auto i = dg(); assert(s.d == 14); assert(i == 12); } /************************************/ S foo9(out dg_t dg) { S s1 = S(7,8,9,10); dg_t abc() { int bar() { s1.d += 4; return s1.c + 3; } return &bar; } dg = abc(); return s1; } void test9() { dg_t dg; S s = foo9(dg); fill(); assert(s.a == 7); assert(s.b == 8); assert(s.c == 9); assert(s.d == 10); auto i = dg(); assert(s.d == 10); assert(i == 12); } /************************************/ dg_t foo10() { dg_t abc() { int x = 7; int bar() { int def() { return x + 3; } return def(); } return &bar; } return abc(); } void test10() { dg_t dg = foo10(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo11() { int x = 7; class T { int bar() { return x + 3; } } T t = new T; return &t.bar; } void test11() { dg_t dg = foo11(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo12() { int x = 7; class T { int bar() { return x + 3; } int xyz() { return bar(); } } T t = new T; return &t.xyz; } void test12() { dg_t dg = foo12(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo13() { int x = 7; class T { int xyz() { int bar() { return x + 3; } return bar(); } } T t = new T; return &t.xyz; } void test13() { dg_t dg = foo13(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo14() { class T { int xyz() { int x = 7; int bar() { return x + 3; } return bar(); } } T t = new T; return &t.xyz; } void test14() { dg_t dg = foo14(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo15() { class T { int x = 7; int xyz() { int bar() { return x + 3; } return bar(); } } T t = new T; return &t.xyz; } void test15() { dg_t dg = foo15(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo16() { int a = 5; class T { int x = 7; int xyz() { int y = 8; int bar() { return a + x + y + 3; } return bar(); } } T t = new T; return &t.xyz; } void test16() { dg_t dg = foo16(); fill(); printf("bar = %d\n", dg()); assert(dg() == 23); } /************************************/ dg_t foo17() { int a = 5; class T { int x = 7; dg_t xyz() { int y = 8; int bar() { return a + x + y + 3; } return &bar; } } T t = new T; return t.xyz(); } void test17() { dg_t dg = foo17(); fill(); printf("bar = %d\n", dg()); assert(dg() == 23); } /************************************/ dg_t dg18; void bar18() { int a = 7; int foo() { return a + 3; } dg18 = &foo; int i = dg18(); assert(i == 10); } void test18() { bar18(); fill(); int i = dg18(); assert(i == 10); } /************************************/ void abc19(void delegate() dg) { dg(); dg(); dg(); } struct S19 { static S19 call(int v) { S19 result; result.v = v; void nest() { result.v += 1; } abc19(&nest); return result; } int a; int v; int x,y,z; } int foo19() { auto s = S19.call(5); return s.v; } void test19() { int i = foo19(); printf("%d\n", i); assert(i == 8); } /************************************/ void enforce20(lazy int msg) { } void test20() { int x; foreach (j; 0 .. 10) { printf("%d\n", j); assert(j == x); x++; enforce20(j); } } /************************************/ void thrash21() { char[128] x = '\xfe'; } void delegate() dg21; int g_input = 11, g_output; void f21() { int i = g_input + 2; class X { // both 'private' and 'final' to make non-virtual private final void actual() { g_output = i; } void go() { actual(); } } dg21 = & (new X).go; } void test21() { f21(); thrash21(); dg21(); assert(g_output == 13); } /************************************/ void thrash22() { char[128] x = '\xfe'; } int gi22; void delegate() dg22; class A22 { int x = 42; void am() { int j; /* Making f access this variable causes f's chain to be am's frame. Otherwise, f's chain would be the A instance. */ void f() { int k = j; void g() { class B { void bm() { gi22 = x; /* No checkedNestedReference for A.am.this, so it is never placed in a closure. */ } } (new B).bm(); } dg22 = &g; } f(); } } void test22() { (new A22).am(); thrash22(); dg22(); assert(gi22 == 42); } /************************************/ // 1759 void test1759() { struct S { int a, b, c; } struct SS { S obj; } static int delegate() makeSum1(S s) { with (s) return { return a + b + c; }; } static int delegate() makeSum2(S[1] sa) { with (sa[0]) return { return a + b + c; }; } static int delegate() makeSum3(SS ss) { with (ss.obj) return { return a + b + c; }; } static int delegate() makeSum4(SS[1] ssa) { with (ssa[0].obj) return { return a + b + c; }; } S s = {15, 30, 45}; SS ss = {s}; int delegate() sum; sum = makeSum1(s); assert(sum() == 90); sum = makeSum2([s]); assert(sum() == 90); sum = makeSum3(ss); assert(sum() == 90); sum = makeSum4([ss]); assert(sum() == 90); } /************************************/ // 1841 int delegate() foo1841() { int stack; int heap = 3; int nested_func() { ++heap; return heap; } return delegate int() { return nested_func(); }; } int delegate() foo1841b() { int stack; int heap = 7; int nested_func() { ++heap; return heap; } int more_nested() { return nested_func(); } return delegate int() { return more_nested(); }; } void test1841() { auto z = foo1841(); auto p = foo1841(); assert(z() == 4); p(); assert(z() == 5); z = foo1841b(); p = foo1841b(); assert(z() == 8); p(); assert(z() == 9); } /************************************/ // 5911 void writeln5911(const(char)[] str) {} void logout5911(lazy const(char)[] msg) { writeln5911(msg); } void test5911() { string str = "hello world"; logout5911((){ return str; }()); // closure 1 try { throw new Exception("exception!!"); } catch (Exception e) { assert(e !is null); logout5911(e.toString()); // closure2 SEGV : e is null. } } /************************************/ // 9685 auto get9685a(alias fun)() { int x = 10; struct Foo { size_t data; @property clone() { return Foo(15); } } return Foo(5); } void test9685a() { uint a = 42; auto bar = get9685a!(() => a)(); auto qux = bar.clone; //printf("bar context pointer : %p\n", bar.tupleof[$-1]); //printf("qux context pointer : %p\n", qux.tupleof[$-1]); assert(bar.tupleof[$-1] == qux.tupleof[$-1]); assert(qux.data == 15); } auto get9685b(alias fun)() { int x = 10; struct Foo { size_t data; @property clone() { return Foo(data + x); } } return Foo(5); } void test9685b() { uint a = 42; auto bar = get9685b!(() => a)(); auto qux = bar.clone; //printf("bar context pointer : %p\n", bar.tupleof[$-1]); //printf("qux context pointer : %p\n", qux.tupleof[$-1]); assert(bar.tupleof[$-1] == qux.tupleof[$-1]); assert(qux.data == 15); } /************************************/ // 12406 auto createDg12406() { static struct Dg { Dg delegate() action; } static void fn(void delegate()) { } int x; fn({ x++; }); // required Dg dg; Dg createDg2() { int x; void unusedFun() { x++; } // required return Dg(() => dg); // lambda returns garbage instead of dg } return dg = Dg(&createDg2); } void test12406() { auto dgs = [createDg12406()]; //printf("dgs[%2d].action = %p:%p\n", 0, dgs[$-1].action.ptr, dgs[$-1].action.funcptr); foreach (i; 1 .. 10+1) { dgs ~= dgs[i-1].action(); //printf("dgs[%2d].action = %p:%p\n", i, dgs[$-1].action.ptr, dgs[$-1].action.funcptr); } foreach (i, dgx; dgs) { if (i % 2 == 0) { // All closures are equal with dgs[0]. assert(dgx.action.ptr is dgs[0].action.ptr); assert(dgx.action.funcptr is dgs[0].action.funcptr); // is: createDg2 } else { // Each closures has unique context. for (size_t j = i + 2; j < dgs.length; j += 2) assert(dgx.action.ptr !is dgs[j].action.ptr); assert(dgx.action.funcptr is dgs[1].action.funcptr); // is: lambda () => dg } } } /************************************/ // 14730 void test14730() { static auto makeS(int x) { struct S { int n; int get() { return x; } // x will be a closure variable } return S(x); } auto s = makeS(1); assert(s.get() == 1); // By inlining get() function call, it's rewritten to: // assert(*(s.tupleof[$-1] + x.offset) == 1); // --> In DotVarExp::toElem(), x->offset should be already nonzero. } // ---- // This is questionable case. Currently it works without any errors, // but not sure it's really intentional struct S14730x(alias f) { auto foo()() { return f(0); } void dummy() {} } auto makeS14730x() //@nogc { int x = 10; S14730x!(a => x) s; //assert(s.foo() == 10); return s; } void test14730x() { auto s = makeS14730x(); assert(s.tupleof[$-1] !is null); // instantiationg foo outside of makeS will place the variable x in closure // *after* the semantic3 completion of makeS() function. assert(s.foo() == 10); } /************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test1759(); test1841(); test5911(); test9685a(); test9685b(); test12406(); test14730(); test14730x(); printf("Success\n"); return 0; }