Skip to content

Commit

Permalink
Merge pull request #4855 from 9rnsr/fix12829
Browse files Browse the repository at this point in the history
Issue 12829 - Wrong error line number for closure allocation in @nogc function
  • Loading branch information
9rnsr committed Jan 31, 2016
2 parents 489d736 + 979c8d5 commit 10a0aa2
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/declaration.h
Expand Up @@ -654,6 +654,7 @@ class FuncDeclaration : public Declaration
FuncDeclaration *isUnique();
bool checkNestedReference(Scope *sc, Loc loc);
bool needsClosure();
bool checkClosure();
bool hasNestedFrameRefs();
void buildResultVar(Scope *sc, Type *tret);
Statement *mergeFrequire(Statement *);
Expand Down
70 changes: 64 additions & 6 deletions src/func.d
Expand Up @@ -2169,13 +2169,13 @@ public:
sc2.callSuper = 0;
sc2.pop();
}
if (needsClosure())

if (checkClosure())
{
if (setGC())
error("@nogc function allocates a closure with the GC");
else
printGCUsage(loc, "using closure causes GC allocation");
// We should be setting errors here instead of relying on the global error count.
//errors = true;
}

/* If function survived being marked as impure, then it is pure
*/
if (flags & FUNCFLAGpurityInprocess)
Expand Down Expand Up @@ -3427,7 +3427,6 @@ public:
for (size_t i = 0; i < closureVars.dim; i++)
{
VarDeclaration v = closureVars[i];
assert(v.isVarDeclaration());
//printf("\tv = %s\n", v->toChars());
for (size_t j = 0; j < v.nestedrefs.dim; j++)
{
Expand Down Expand Up @@ -3496,6 +3495,65 @@ public:
return true;
}

/***********************************************
* Check that the function contains any closure.
* If it's @nogc, report suitable errors.
* This is mostly consistent with FuncDeclaration::needsClosure().
*
* Returns:
* true if any errors occur.
*/
final bool checkClosure()
{
if (!needsClosure())
return false;

if (setGC())
{
error("is @nogc yet allocates closures with the GC");
if (global.gag) // need not report supplemental errors
return true;
}
else
{
printGCUsage(loc, "using closure causes GC allocation");
return false;
}

FuncDeclarations a;
foreach (v; closureVars)
{
foreach (f; v.nestedrefs)
{
assert(f !is this);

LcheckAncestorsOfANestedRef:
for (Dsymbol s = f; s && s !is this; s = s.parent)
{
auto fx = s.isFuncDeclaration();
if (!fx)
continue;
if (fx.isThis() ||
fx.tookAddressOf ||
checkEscapingSiblings(fx, this))
{
foreach (f2; a)
{
if (f2 == f)
break LcheckAncestorsOfANestedRef;
}
a.push(f);
.errorSupplemental(f.loc, "%s closes over variable %s at %s",
f.toPrettyChars(), v.toChars(), v.loc.toChars());
break LcheckAncestorsOfANestedRef;
}
}
}
}

return true;
}

/***********************************************
* Determine if function's variables are referenced by a function
* nested within it.
Expand Down
37 changes: 37 additions & 0 deletions test/fail_compilation/diag12829.d
@@ -0,0 +1,37 @@
/*
TEST_OUTPUT:
---
fail_compilation/diag12829.d(12): Error: function diag12829.test1 is @nogc yet allocates closures with the GC
fail_compilation/diag12829.d(15): diag12829.test1.__lambda1 closes over variable x at fail_compilation/diag12829.d(14)
fail_compilation/diag12829.d(19): diag12829.test1.bar closes over variable x at fail_compilation/diag12829.d(14)
fail_compilation/diag12829.d(26): Error: function diag12829.test2 is @nogc yet allocates closures with the GC
fail_compilation/diag12829.d(31): diag12829.test2.S.foo closes over variable x at fail_compilation/diag12829.d(28)
---
*/

auto test1() @nogc
{
int x;
void delegate() @nogc foo = () {
int y = x;
};

void bar()
{
int y = x;
}
auto dg = &bar;
}

auto test2() @nogc
{
int x;
struct S
{
void foo()
{
int y = x;
}
}
return S();
}
6 changes: 4 additions & 2 deletions test/fail_compilation/nogc3.d
Expand Up @@ -44,8 +44,10 @@ fail_compilation/nogc3.d(36): Error: @nogc function 'nogc3.testCall' cannot call
/*
TEST_OUTPUT:
---
fail_compilation/nogc3.d(51): Error: function nogc3.testClosure1 @nogc function allocates a closure with the GC
fail_compilation/nogc3.d(63): Error: function nogc3.testClosure3 @nogc function allocates a closure with the GC
fail_compilation/nogc3.d(53): Error: function nogc3.testClosure1 is @nogc yet allocates closures with the GC
fail_compilation/nogc3.d(56): nogc3.testClosure1.bar closes over variable x at fail_compilation/nogc3.d(55)
fail_compilation/nogc3.d(65): Error: function nogc3.testClosure3 is @nogc yet allocates closures with the GC
fail_compilation/nogc3.d(68): nogc3.testClosure3.bar closes over variable x at fail_compilation/nogc3.d(67)
---
*/
@nogc auto testClosure1()
Expand Down

0 comments on commit 10a0aa2

Please sign in to comment.