Skip to content

Commit

Permalink
fix Issue 18282 - [Scope][DIP1000]Assignment of local variable to var…
Browse files Browse the repository at this point in the history
…iable not recognized by compiler
  • Loading branch information
WalterBright committed Mar 15, 2018
1 parent cad484b commit ac02242
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 7 deletions.
18 changes: 15 additions & 3 deletions src/dmd/dcast.d
Expand Up @@ -24,6 +24,7 @@ import dmd.dscope;
import dmd.dstruct;
import dmd.dsymbol;
import dmd.errors;
import dmd.escape;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
Expand Down Expand Up @@ -2070,14 +2071,24 @@ extern (C++) Expression castTo(Expression e, Scope* sc, Type t)
{
printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars());
}

ArrayLiteralExp ae = e;

Type tb = t.toBasetype();
if (tb.ty == Tarray && global.params.vsafe)
{
if (checkArrayLiteralEscape(sc, ae, false))
{
result = new ErrorExp();
return;
}
}

if (e.type == t)
{
result = e;
return;
}
ArrayLiteralExp ae = e;

Type tb = t.toBasetype();
Type typeb = e.type.toBasetype();

if ((tb.ty == Tarray || tb.ty == Tsarray) &&
Expand Down Expand Up @@ -2166,6 +2177,7 @@ extern (C++) Expression castTo(Expression e, Scope* sc, Type t)

override void visit(AssocArrayLiteralExp e)
{
//printf("AssocArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars());
if (e.type == t)
{
result = e;
Expand Down
51 changes: 50 additions & 1 deletion src/dmd/escape.d
Expand Up @@ -30,6 +30,55 @@ import dmd.tokens;
import dmd.visitor;
import dmd.arraytypes;

/******************************************
* Array literal is going to be allocated on the GC heap.
* Check its elements to see if any would escape by going on the heap.
* Params:
* sc = used to determine current function and module
* ae = array literal expression
* gag = do not print error messages
* Returns:
* true if any elements escaped
*/
bool checkArrayLiteralEscape(Scope *sc, ArrayLiteralExp ae, bool gag)
{
bool errors;
if (ae.basis)
errors = checkReturnEscape(sc, ae.basis, gag);
foreach (ex; *ae.elements)
{
if (ex)
errors |= checkReturnEscape(sc, ex, gag);
}
return errors;
}

/******************************************
* Associative array literal is going to be allocated on the GC heap.
* Check its elements to see if any would escape by going on the heap.
* Params:
* sc = used to determine current function and module
* ae = associative array literal expression
* gag = do not print error messages
* Returns:
* true if any elements escaped
*/
bool checkAssocArrayLiteralEscape(Scope *sc, AssocArrayLiteralExp ae, bool gag)
{
bool errors;
foreach (ex; *ae.keys)
{
if (ex)
errors |= checkReturnEscape(sc, ex, gag);
}
foreach (ex; *ae.values)
{
if (ex)
errors |= checkReturnEscape(sc, ex, gag);
}
return errors;
}

/****************************************
* Function parameter par is being initialized to arg,
* and par may escape.
Expand Down Expand Up @@ -952,7 +1001,7 @@ private void escapeByValue(Expression e, EscapeByResults* er)

override void visit(IndexExp e)
{
if (e.type.hasPointers())
if (e.e1.type.toBasetype().ty == Tsarray)
{
e.e1.accept(this);
}
Expand Down
6 changes: 6 additions & 0 deletions src/dmd/expressionsem.d
Expand Up @@ -1773,6 +1773,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor

semanticTypeInfo(sc, e.type);

if (global.params.vsafe)
{
if (checkAssocArrayLiteralEscape(sc, e, false))
return setError();
}

result = e;
}

Expand Down
6 changes: 3 additions & 3 deletions test/fail_compilation/retscope3.d
Expand Up @@ -6,8 +6,8 @@ PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
fail_compilation/retscope3.d(2009): Error: scope variable `arr` may not be returned
fail_compilation/retscope3.d(2018): Error: scope variable `arr` may not be returned
fail_compilation/retscope3.d(2008): Error: returning `& i` escapes a reference to local variable `i`
fail_compilation/retscope3.d(2017): Error: returning `S2000(& i)` escapes a reference to local variable `i`
---
*/

Expand All @@ -21,7 +21,7 @@ int* bar1()
{
int i;
int*[] arr = [ &i ];
return arr[0]; // Error: scope variable arr may not be returned
return arr[0];
}

struct S2000 { int* p; }
Expand Down
54 changes: 54 additions & 0 deletions test/fail_compilation/test18282.d
@@ -0,0 +1,54 @@
/* REQUIRED_ARGS: -dip1000
TEST_OUTPUT:
---
fail_compilation/test18282.d(25): Error: scope variable `aa` may not be returned
fail_compilation/test18282.d(34): Error: returning `& i` escapes a reference to local variable `i`
fail_compilation/test18282.d(35): Error: returning `& i` escapes a reference to local variable `i`
fail_compilation/test18282.d(36): Error: scope variable `staa` may not be returned
fail_compilation/test18282.d(44): Error: returning `S2000(& i)` escapes a reference to local variable `i`
fail_compilation/test18282.d(53): Error: returning `& i` escapes a reference to local variable `i`
fail_compilation/test18282.d(53): Error: returning `& c` escapes a reference to local variable `c`
---
*/

// https://issues.dlang.org/show_bug.cgi?id=18282

string* f() @safe
{
scope string*[] ls;
return ls[0];
}

int* g() @safe
{
scope int*[3] aa;
return aa[0];
}

@safe:

auto bar1()
{
int i = void;
int*[1] staa = [ &i ];
auto dyna = [ &i ];
int*[ ] dynb = [ &i ];
return staa[0];
}

struct S2000 { int* p; }

S2000 bar2()
{
int i;
S2000[] arr = [ S2000(&i) ];
return arr[0];
}


void bar2()
{
int i;
char c;
char*[int*] aa = [ &i : &c ];
}

0 comments on commit ac02242

Please sign in to comment.