Skip to content

Commit

Permalink
fix Issue 17423 - pointer assignment to in member function is not acc…
Browse files Browse the repository at this point in the history
…ounted for
  • Loading branch information
WalterBright committed Mar 12, 2018
1 parent 0bdfedc commit 9fbf061
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 8 deletions.
4 changes: 2 additions & 2 deletions src/dmd/escape.d
Expand Up @@ -1009,7 +1009,7 @@ private void escapeByValue(Expression e, EscapeByResults* er)
if (i - j < nparams && i >= j)
{
Parameter p = Parameter.getNth(tf.parameters, i - j);
const stc = tf.parameterStorageClass(p);
const stc = tf.parameterStorageClass(null, p);
if ((stc & (STC.scope_)) && (stc & STC.return_))
arg.accept(this);
else if ((stc & (STC.ref_)) && (stc & STC.return_))
Expand Down Expand Up @@ -1207,7 +1207,7 @@ private void escapeByRef(Expression e, EscapeByResults* er)
if (i - j < nparams && i >= j)
{
Parameter p = Parameter.getNth(tf.parameters, i - j);
const stc = tf.parameterStorageClass(p);
const stc = tf.parameterStorageClass(null, p);
if ((stc & (STC.out_ | STC.ref_)) && (stc & STC.return_))
arg.accept(this);
else if ((stc & STC.scope_) && (stc & STC.return_))
Expand Down
3 changes: 2 additions & 1 deletion src/dmd/expressionsem.d
Expand Up @@ -808,8 +808,9 @@ private bool functionParameters(Loc loc, Scope* sc, TypeFunction tf, Type tthis,
}
//printf("arg: %s\n", arg.toChars());
//printf("type: %s\n", arg.type.toChars());
//printf("param: %s\n", p.toChars());

if (tf.parameterEscapes(p))
if (tf.parameterEscapes(tthis, p))
{
/* Argument value can escape from the called function.
* Check arg to see if it matters.
Expand Down
30 changes: 25 additions & 5 deletions src/dmd/mtype.d
Expand Up @@ -4964,35 +4964,36 @@ extern (C++) final class TypeFunction : TypeNext
* the value of p can 'escape' the scope of the function.
* This is useful to minimize the needed annotations for the parameters.
* Params:
* tthis = type of `this` parameter, null if none
* p = parameter to this function
* Returns:
* true if escapes via assignment to global or through a parameter
*/
bool parameterEscapes(Parameter p)
bool parameterEscapes(Type tthis, Parameter p)
{
/* Scope parameters do not escape.
* Allow 'lazy' to imply 'scope' -
* lazy parameters can be passed along
* as lazy parameters to the next function, but that isn't
* escaping.
*/
if (parameterStorageClass(p) & (STC.scope_ | STC.lazy_))
if (parameterStorageClass(tthis, p) & (STC.scope_ | STC.lazy_))
return false;
return true;
}


/************************************
* Take the specified storage class for p,
* and use the function signature to infer whether
* STC.scope_ and STC.return_ should be OR'd in.
* (This will not affect the name mangling.)
* Params:
* p = one of the parameters to 'this'
* tthis = type of `this` parameter, null if none
* p = parameter to this function
* Returns:
* storage class with STC.scope_ or STC.return_ OR'd in
*/
final StorageClass parameterStorageClass(Parameter p)
final StorageClass parameterStorageClass(Type tthis, Parameter p)
{
//printf("parameterStorageClass(p: %s)\n", p.toChars());
auto stc = p.storageClass;
Expand All @@ -5012,6 +5013,7 @@ extern (C++) final class TypeFunction : TypeNext
// See if p can escape via any of the other parameters
if (purity == PURE.weak)
{
// Check escaping through parameters
const dim = Parameter.dim(parameters);
foreach (const i; 0 .. dim)
{
Expand All @@ -5036,6 +5038,24 @@ extern (C++) final class TypeFunction : TypeNext
return stc;
}
}

// Check escaping through `this`
if (tthis && tthis.isMutable())
{
auto tb = tthis.toBasetype();
AggregateDeclaration ad;
if (tb.ty == Tclass)
ad = (cast(TypeClass)tb).sym;
else if (tb.ty == Tstruct)
ad = (cast(TypeStruct)tb).sym;
else
assert(0);
foreach (VarDeclaration v; ad.fields)
{
if (v.hasPointers())
return stc;
}
}
}

stc |= STC.scope_;
Expand Down
29 changes: 29 additions & 0 deletions test/fail_compilation/test17423.d
@@ -0,0 +1,29 @@
/* REQUIRED_ARGS: -dip1000
TEST_OUTPUT:
---
fail_compilation/test17423.d(26): Error: reference to local `this` assigned to non-scope parameter `dlg` calling test17423.Bar.opApply
---
*/

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

struct Bar
{
int delegate(int) @safe myDlg;

auto opApply(int delegate(int) @safe dlg) @safe {
myDlg = dlg;
return 0;
}
}

struct Foo
{
Bar o;
int i = 3;

this(int x) @safe {
foreach(_; o) { i = 0; }
i = x;
}
}

0 comments on commit 9fbf061

Please sign in to comment.