December 17, 2016
On Saturday, 17 December 2016 at 14:09:59 UTC, Walter Bright wrote:
> On 12/16/2016 9:08 AM, Mathias Lang wrote:
>> void main () @safe
>> {
>>     int* a = escape();
>> }
>>
>> int* escape () @safe
>> {
>>     int i;
>>     int*[3] a = [ &i, null, null ];
>>     return bar(&a[0]);
>> }
>>
>> int* bar (scope int** x) @safe
>> {
>>     return foo(*x);
>> }
>>
>> int* foo (int* x) @safe { return x; }
>
> https://github.com/dlang/dmd/pull/6329

Merged both of your P.R. in a local branch, and tested again:

```
void main () @safe
{
    int[] a = escape();
}

int[] escape () @safe
{
    Foo f;
    return f.foo;
}

struct Foo
{
    int[10] v;
    int[] foo () return @safe { return this.v; }
}
```

> Taking the address of a scope pointer is invalid

Thanks for the clarification. I think this will prove pretty limiting in the future. For example, a stack allocator will return data that is already typed as `scope`, and as a consequence, interior pointers will not be expressible. I'll see if I can form an example in terms of code.


And since I started toying around with aggregate methods, here's another reason why changing the STC of a field member is a very bad idea:
```
void main () @safe
{
    int* a = escape();
}

int* escape () @safe
{
    int i;
    Foo f;
    f.v = &i;
    return f.foo;
}

struct Foo
{
    int* v;
    int* foo () @safe { return this.v; }
}
```

Note: The definition of `Foo` might be in another module, and just visible via an header (.di) file.
December 17, 2016
On 12/17/2016 7:38 AM, Mathias Lang wrote:
>> Taking the address of a scope pointer is invalid
> Thanks for the clarification. I think this will prove pretty limiting in the
> future. For example, a stack allocator will return data that is already typed as
> `scope`, and as a consequence, interior pointers will not be expressible. I'll
> see if I can form an example in terms of code.

It should work fine.


> And since I started toying around with aggregate methods, here's another reason
> why changing the STC of a field member is a very bad idea:

It doesn't change the STC of field members. Only of locals.

---

I'll investigate the reports. Thanks!
December 18, 2016
On Sunday, 18 December 2016 at 02:43:59 UTC, Walter Bright wrote:

Just a general remark, not specific to the content of this conversation.

Being a bit more specific in answers easily makes them less misunderstandable.

> On 12/17/2016 7:38 AM, Mathias Lang wrote:
>> For example, a stack allocator will return data that is already typed as
>> `scope`, and as a consequence, interior pointers will not be expressible. I'll
>> see if I can form an example in terms of code.
>
> It should work fine.

What does "it" refer to here, doesn't hurt much to write "Internal pointers in scope structs" or so.
Equally "work fine" doesn't state how the "it" is supposed to work.

>> And since I started toying around with aggregate methods, here's another reason
>> why changing the STC of a field member is a very bad idea:
>
> It doesn't change the STC of field members. Only of locals.

What's it here? Your DIP or the dmd implementation?
December 18, 2016
On Saturday, 17 December 2016 at 07:29:17 UTC, Walter Bright wrote:
> On 12/16/2016 9:08 AM, Mathias Lang wrote:
>> As long as we have:
>> - A way to take the address of `scope` pointers
>
> Taking the address of a scope pointer is invalid, I'll fix the method you used to do it.

What is the reasoning for disallowing that?
Is dealing with second order indirections (scope int**) somehow different from from other escape checks?

December 18, 2016
On Sunday, 18 December 2016 at 04:03:55 UTC, Martin Nowak wrote:
>> Taking the address of a scope pointer is invalid, I'll fix the method you used to do it.
>
> What is the reasoning for disallowing that?
> Is dealing with second order indirections (scope int**) somehow different from from other escape checks?

Also see https://github.com/dlang/dmd/pull/6328/files#r92933626 on that question.
December 17, 2016
On 12/17/2016 7:56 PM, Martin Nowak wrote:
>> On 12/17/2016 7:38 AM, Mathias Lang wrote:
>>> For example, a stack allocator will return data that is already typed as
>>> `scope`, and as a consequence, interior pointers will not be expressible. I'll
>>> see if I can form an example in terms of code.
>>
>> It should work fine.
>
> What does "it" refer to here, doesn't hurt much to write "Internal pointers in
> scope structs" or so.
> Equally "work fine" doesn't state how the "it" is supposed to work.

A stack allocator is conceptually returning a slice of a static array allocated on the stack. This works with scope.

Understanding scope always goes back to understanding how it works with pointers and addresses. Adding layers of abstraction over that can be confusing by obfuscating that relationship, but rewrite the abstract as pointers and addresses, and the behavior then becomes clear.

The bugs Mathias has posted have (so far) all been the result of an abstraction not conforming to how pointers and addresses work, due to a bug in dmd.


>>> And since I started toying around with aggregate methods, here's another reason
>>> why changing the STC of a field member is a very bad idea:
>>
>> It doesn't change the STC of field members. Only of locals.
>
> What's it here? Your DIP or the dmd implementation?

The dmd implementation.
December 17, 2016
On 12/17/2016 8:03 PM, Martin Nowak wrote:
> On Saturday, 17 December 2016 at 07:29:17 UTC, Walter Bright wrote:
>> On 12/16/2016 9:08 AM, Mathias Lang wrote:
>>> As long as we have:
>>> - A way to take the address of `scope` pointers
>>
>> Taking the address of a scope pointer is invalid, I'll fix the method you used
>> to do it.
>
> What is the reasoning for disallowing that?

scope is not transitive, and there's no way to declare a scope pointer to a scope pointer.

> Is dealing with second order indirections (scope int**) somehow different from
> from other escape checks?

Yes. Only the top level is checked. By disallowing taking the address of a scope variable, only the top level needs to be checked.


December 17, 2016
On 12/17/2016 7:38 AM, Mathias Lang wrote:
> void main () @safe
> {
>     int[] a = escape();
> }
>
> int[] escape () @safe
> {
>     Foo f;
>     return f.foo;
> }
>
> struct Foo
> {
>     int[10] v;
>     int[] foo () return @safe { return this.v; }
> }

I've said it's all about pointers and addresses. So let's remove the abstractions, and rewrite it in the equivalent pointers and addresses form:

```
void main () @safe
{
    int* a = escape();
}

int* escape () @safe
{
    int f;
    return foo(f);  // Error: escaping reference to local variable f
}

int* foo (return ref int i) @safe { return &i; }
```

and indeed it does fail to compile. So the bug in the compiler is failing to recognize the abstract version of the pointers and addresses logic.


December 17, 2016
On 12/17/2016 10:29 PM, Walter Bright wrote:
> So the bug in the compiler is failing to
> recognize the abstract version of the pointers and addresses logic.

https://github.com/dlang/dmd/pull/6330
December 17, 2016
On 12/17/2016 7:38 AM, Mathias Lang wrote:
> int* escape () @safe
> {
>     int i;
>     Foo f;
>     f.v = &i;
>     return f.foo;
> }
>
> struct Foo
> {
>     int* v;
>     int* foo () @safe { return this.v; }
> }

Rewriting to the equivalent:

```
int* escape() @safe
{
    int i;
    Foo f;
    f.v = &i;
    return foo(g);  // Error: scope variable f assigned to non-scope
                    // parameter g calling bug.foo
}

struct Foo
{
    int* v;
}

int* foo(ref Foo g) @safe { return g.v; }
```

So the trouble here is dmd not recognizing that f.foo() is the same as foo(f).