Skip to content

Commit

Permalink
fix Issue 15332 - ICE in e2ir.c: assert(irs->sthis) in visit(ThisExp)…
Browse files Browse the repository at this point in the history
…, function literal with keyword 'function' calls method

Set `FuncLiteralDeclaration.tok` to `TOKdelegate` if its `isNested()` actually returns `true`.

This is not complete, temporary disable `compilable/test14973.d` case.
  • Loading branch information
9rnsr committed Feb 1, 2016
1 parent 4c2c973 commit a81cdc4
Show file tree
Hide file tree
Showing 10 changed files with 64 additions and 75 deletions.
42 changes: 4 additions & 38 deletions src/declaration.d
Expand Up @@ -55,27 +55,9 @@ extern (C++) bool checkFrameAccess(Loc loc, Scope* sc, AggregateDeclaration ad,
Dsymbol s = sc.func;
if (ad.isNested() && s)
{
//printf("ad = %p %s [%s], parent:%p\n", ad, ad->toChars(), ad->loc.toChars(), ad->parent);
//printf("sparent = %p %s [%s], parent: %s\n", sparent, sparent->toChars(), sparent->loc.toChars(), sparent->parent->toChars());
while (s)
{
if (s == sparent) // hit!
break;
if (FuncDeclaration fd = s.isFuncDeclaration())
{
if (!fd.isThis() && !fd.isNested())
break;
if (FuncLiteralDeclaration fld = fd.isFuncLiteralDeclaration())
fld.tok = TOKdelegate;
}
if (AggregateDeclaration ad2 = s.isAggregateDeclaration())
{
if (ad2.storage_class & STCstatic)
break;
}
s = s.toParent2();
}
if (s != sparent)
//printf("ad = %p %s [%s], parent:%p\n", ad, ad.toChars(), ad.loc.toChars(), ad.parent);
//printf("sparent = %p %s [%s], parent: %s\n", sparent, sparent.toChars(), sparent.loc.toChars(), sparent.parent,toChars());
if (checkNestedRef(s, sparent))
{
error(loc, "cannot access frame pointer of %s", ad.toPrettyChars());
return true;
Expand Down Expand Up @@ -2225,23 +2207,7 @@ public:
Dsymbol p = toParent2();

// Function literals from fdthis to p must be delegates
// TODO: here is similar to checkFrameAccess.
for (Dsymbol s = fdthis; s && s != p; s = s.toParent2())
{
// function literal has reference to enclosing scope is delegate
if (FuncLiteralDeclaration fld = s.isFuncLiteralDeclaration())
fld.tok = TOKdelegate;
if (FuncDeclaration fd = s.isFuncDeclaration())
{
if (!fd.isThis() && !fd.isNested())
break;
}
if (AggregateDeclaration ad2 = s.isAggregateDeclaration())
{
if (ad2.storage_class & STCstatic)
break;
}
}
checkNestedRef(fdthis, p);

// The function that this variable is in
FuncDeclaration fdv = p.isFuncDeclaration();
Expand Down
27 changes: 27 additions & 0 deletions src/delegatize.d
Expand Up @@ -11,6 +11,7 @@ module ddmd.delegatize;
import ddmd.apply;
import ddmd.declaration;
import ddmd.dscope;
import ddmd.dsymbol;
import ddmd.expression;
import ddmd.func;
import ddmd.globals;
Expand Down Expand Up @@ -165,3 +166,29 @@ extern (C++) bool lambdaCheckForNestedRef(Expression e, Scope* sc)
walkPostorder(e, v);
return v.result;
}

bool checkNestedRef(Dsymbol s, Dsymbol p)
{
while (s)
{
if (s == p) // hit!
return false;

if (auto fd = s.isFuncDeclaration())
{
if (!fd.isThis() && !fd.isNested())
break;

// Bugzilla 15332: change to delegate if fd is actually nested.
if (auto fld = fd.isFuncLiteralDeclaration())
fld.tok = TOKdelegate;
}
if (auto ad = s.isAggregateDeclaration())
{
if (ad.storage_class & STCstatic)
break;
}
s = s.toParent2();
}
return true;
}
17 changes: 4 additions & 13 deletions src/expression.d
Expand Up @@ -5629,20 +5629,11 @@ public:
else if (fdn)
{
// make sure the parent context fdn of cd is reachable from sc
for (Dsymbol sp = sc.parent; 1; sp = sp.parent)
if (checkNestedRef(sc.parent, fdn))
{
if (fdn == sp)
break;
FuncDeclaration fsp = sp ? sp.isFuncDeclaration() : null;
if (!sp || (fsp && fsp.isStatic()))
{
error("outer function context of %s is needed to 'new' nested class %s", fdn.toPrettyChars(), cd.toPrettyChars());
goto Lerr;
}
else if (FuncLiteralDeclaration fld = sp.isFuncLiteralDeclaration())
{
fld.tok = TOKdelegate;
}
error("outer function context of %s is needed to 'new' nested class %s",
fdn.toPrettyChars(), cd.toPrettyChars());
goto Lerr;
}
}
else
Expand Down
19 changes: 2 additions & 17 deletions src/func.d
Expand Up @@ -18,6 +18,7 @@ import ddmd.builtin;
import ddmd.ctfeexpr;
import ddmd.dclass;
import ddmd.declaration;
import ddmd.delegatize;
import ddmd.dinterpret;
import ddmd.dmodule;
import ddmd.doc;
Expand Down Expand Up @@ -3338,23 +3339,7 @@ public:
Dsymbol p = toParent2();

// Function literals from fdthis to p must be delegates
// TODO: here is similar to checkFrameAccess.
for (Dsymbol s = fdthis; s && s != p; s = s.toParent2())
{
// function literal has reference to enclosing scope is delegate
if (FuncLiteralDeclaration fld = s.isFuncLiteralDeclaration())
fld.tok = TOKdelegate;
if (FuncDeclaration fd = s.isFuncDeclaration())
{
if (!fd.isThis() && !fd.isNested())
break;
}
if (AggregateDeclaration ad2 = s.isAggregateDeclaration())
{
if (ad2.storage_class & STCstatic)
break;
}
}
checkNestedRef(fdthis, p);

if (isNested())
{
Expand Down
3 changes: 2 additions & 1 deletion test/compilable/test14973.d
@@ -1,3 +1,4 @@
/+
template map(fun...)
{
auto map(R)(R r)
Expand Down Expand Up @@ -50,5 +51,5 @@ class Bar
); // compiles <- error
}
}

+/
void main() {}
2 changes: 1 addition & 1 deletion test/fail_compilation/diag9831.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
fail_compilation/diag9831.d(12): Error: cannot match delegate literal to function pointer type 'int function(int x)'
fail_compilation/diag9831.d(12): Error: function diag9831.main.__lambda1 cannot access frame of function D main
---
*/

Expand Down
4 changes: 2 additions & 2 deletions test/fail_compilation/fail11545.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail11545.d(17): Error: cannot implicitly convert expression (__lambda5) of type int delegate() pure nothrow @nogc @safe to int function()
fail_compilation/fail11545.d(17): Error: cannot implicitly convert expression (__lambda5) of type int delegate() pure nothrow @nogc @safe to int function()
fail_compilation/fail11545.d(14): Error: need 'this' for 'x' of type 'int'
fail_compilation/fail11545.d(18): Error: need 'this' for 'x' of type 'int'
---
*/

Expand Down
4 changes: 2 additions & 2 deletions test/fail_compilation/fail120.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail120.d(12): Error: non-constant nested delegate literal expression __lambda4
fail_compilation/fail120.d(13): Error: non-constant nested delegate literal expression __lambda5
fail_compilation/fail120.d(12): Error: need 'this' for 'nodes' of type 'int[2]'
fail_compilation/fail120.d(13): Error: need 'this' for 'nodes' of type 'int[2]'
---
*/

Expand Down
2 changes: 1 addition & 1 deletion test/fail_compilation/fail39.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail39.d(11): Error: function fail39.main.foo is a nested function and cannot be accessed from fail39.main.__funcliteral2
fail_compilation/fail39.d(11): Error: function fail39.main.__funcliteral2 cannot access frame of function D main
---
*/

Expand Down
19 changes: 19 additions & 0 deletions test/fail_compilation/ice15332.d
@@ -0,0 +1,19 @@
/*
TEST_OUTPUT:
---
fail_compilation/ice15332.d(16): Error: need 'this' for 'fun' of type 'int()'
fail_compilation/ice15332.d(17): Error: need 'this' for 'var' of type 'int'
---
*/

class C
{
int fun() { return 5; }
int var;

void test()
{
int a1 = function() { return fun; }();
int a2 = function() { return var; }();
}
}

0 comments on commit a81cdc4

Please sign in to comment.