September 22, 2019
On 2019-09-22 04:29, Mike Franklin wrote:
> @safe:
> 
> // Exhibit A
> //--------------------------
> int getValue1(int* i)
> {
>      return *i;
> }
> 
> int* foo1()
> {
>      int value;
>      int[] y;
>      y ~= getValue1(&value); //Error: reference to local variable `value` assigned to non-scope parameter `i` calling `onlineapp.getValue1`
>      return &y[0];
> }
> 
> // Exhibit B
> //--------------------------
> int getValue2(ref int i)
> {
>      return i;
> }
> 
> int* foo2()
> {
>      int value;
>      int[] y;
>      y ~= getValue2(value); // No error
>      return &y[0];
> }
> 
> // Exhibit C (Same as Exhibit A, but with `scope` attribute on `i`)
> //--------------------------
> int getValue3(scope int* i)
> {
>      return *i;
> }
> 
> int* foo3()
> {
>      int value;
>      int[] y;
>      y ~= getValue3(&value); // No error
>      return &y[0];
> }
> 
> Compile with `-preview=dip1000`.  See it live at https://run.dlang.io/is/0zODCr
> 
> So, there's an inconsistency.
> 
> Possibility 1:
> Exhibit A should not emit an error
> 
> Possibility 2:
> Exhibit B should require the `scope` attribute on `i` or emit an error if `foo2`.
> 
> Which is it?  Where's the bug?  Shouldn't the compiler treat `int* i` and `ref i` consistently?

I think this is working as intended.

In Exhibit A, `i` is a pointer and may escape the function `getValue1`. Therefore it's not allowed to pass the address of a local variable to it.

In Exhibit B, `i` is a reference and cannot escape the function `getValue2`.

In Exhibit C, the `scope` annotation of `i` makes sure that `i` cannot escape the function `getValue3`. Therefore it's ok to pass the address of a local variable to it.

-- 
/Jacob Carlborg
September 22, 2019
On Sunday, 22 September 2019 at 11:03:29 UTC, Jacob Carlborg wrote:

> In Exhibit B, `i` is a reference and cannot escape the function `getValue2`.

Ok, that is an interesting observation.  If that's the case, then I don't see any reason to ever annotate a `ref` parameter with `scope`.  In other words, for `ref` parameters `scope` is inferred (or implied).  Do you agree with that?


September 22, 2019
On Sunday, 22 September 2019 at 11:03:29 UTC, Jacob Carlborg wrote:

> In Exhibit B, `i` is a reference and cannot escape the function `getValue2`.

Actually, ag0aep6g's demonstration at https://forum.dlang.org/post/qm7cib$2n07$1@digitalmars.com proves that statement false.  Unless it is a bug in the compiler that one can convert a `ref` to a pointer in `@safe` code.


September 22, 2019
On Sunday, 22 September 2019 at 11:42:44 UTC, Mike Franklin wrote:
> On Sunday, 22 September 2019 at 11:03:29 UTC, Jacob Carlborg wrote:
>
>> In Exhibit B, `i` is a reference and cannot escape the function `getValue2`.
>
> Actually, ag0aep6g's demonstration at https://forum.dlang.org/post/qm7cib$2n07$1@digitalmars.com proves that statement false.  Unless it is a bug in the compiler that one can convert a `ref` to a pointer in `@safe` code.

Yes. The compiler only looks at the signature when it is checking the call site of said function.
September 22, 2019
On 2019-09-22 13:22, Mike Franklin wrote:

> Ok, that is an interesting observation.  If that's the case, then I don't see any reason to ever annotate a `ref` parameter with `scope`.  In other words, for `ref` parameters `scope` is inferred (or implied).  Do you agree with that?

Yes.

-- 
/Jacob Carlborg
September 22, 2019
On 2019-09-22 13:42, Mike Franklin wrote:

> Actually, ag0aep6g's demonstration at https://forum.dlang.org/post/qm7cib$2n07$1@digitalmars.com proves that statement false.  Unless it is a bug in the compiler that one can convert a `ref` to a pointer in `@safe` code.

That might be a bug in the compiler. Adding `scope` to the reference doesn't help.

But with DIP1000, there's some documentation missing and I think only Walter knows how it should behave.

-- 
/Jacob Carlborg
September 22, 2019
On Sunday, 22 September 2019 at 16:32:02 UTC, Jacob Carlborg wrote:
> On 2019-09-22 13:22, Mike Franklin wrote:
>
>> Ok, that is an interesting observation.  If that's the case, then I don't see any reason to ever annotate a `ref` parameter with `scope`.  In other words, for `ref` parameters `scope` is inferred (or implied).  Do you agree with that?
>
> Yes.

According to DIP1000 (https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1000.md#identity-function) `scope ref` is a thing, so I guess `scope` can't be inferred or implied for `ref`.

I don't know.  I think Walter is the only one that can clear this up.
September 22, 2019
On Sunday, 22 September 2019 at 17:01:59 UTC, Mike Franklin wrote:
> On Sunday, 22 September 2019 at 16:32:02 UTC, Jacob Carlborg wrote:
>> On 2019-09-22 13:22, Mike Franklin wrote:
>>
>>> Ok, that is an interesting observation.  If that's the case, then I don't see any reason to ever annotate a `ref` parameter with `scope`.  In other words, for `ref` parameters `scope` is inferred (or implied).  Do you agree with that?
>>
>> Yes.
>
> According to DIP1000 (https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1000.md#identity-function) `scope ref` is a thing, so I guess `scope` can't be inferred or implied for `ref`.
>
> I don't know.  I think Walter is the only one that can clear this up.

Yes, `scope ref` is definitely a thing.  Compare the following.

// Exhibit C
@safe:

struct A
{
     int* ptr;
}

int* gptr;

void foo(ref A a)
{
     gptr = a.ptr; // error, can't leak borrowed a.ptr into global context
}

https://run.dlang.io/is/ZU780c


// Exhibit D
@safe:

struct A
{
     int* ptr;
}

int* gptr;

void foo(scope ref A a)
{
     gptr = a.ptr; // error, can't leak borrowed a.ptr into global context
}

https://run.dlang.io/is/ZU780c

This was taken from the discussion at https://forum.dlang.org/post/twgsrfcolypurgylhizh@forum.dlang.org
September 22, 2019
On Sunday, 22 September 2019 at 08:49:14 UTC, ag0aep6g wrote:

> Then it's possibility 2: `foo2` should error. Your code can easily be expanded to demonstrate memory corruption:
>
> ----
> @safe:
>
> immutable(int)* ip;
>
> // Exhibit B
> //--------------------------
> int getValue2(ref immutable int i)
> {
>     immutable int* my_ip = &i;
>     ip = my_ip;
>     return i;
> }
>
> int* foo2()
> {
>     immutable int value = 42;
>     int[] y;
>     y ~= getValue2(value); // No error
>     return &y[0];
> }
>
> void main()
> {
>     auto p = foo2();
>     import std.stdio;
>     writeln(*ip); /* Prints "42". */
>     writeln(*ip); /* Prints garbage. An immutable value has changed. */
> }
> ----

Interestingly, taking the address of a `ref` in `@safe` code is prevented, but only when compiling *without* -preview=dip1000.  See https://run.dlang.io/is/GArFzk

That's seems like a bug to me.
September 22, 2019
On 2019-09-22 19:26, Mike Franklin wrote:
> On Sunday, 22 September 2019 at 08:49:14 UTC, ag0aep6g wrote:
> 
>> Then it's possibility 2: `foo2` should error. Your code can easily be expanded to demonstrate memory corruption:
>>
>> ----
>> @safe:
>>
>> immutable(int)* ip;
>>
>> // Exhibit B
>> //--------------------------
>> int getValue2(ref immutable int i)
>> {
>>     immutable int* my_ip = &i;
>>     ip = my_ip;
>>     return i;
>> }
>>
>> int* foo2()
>> {
>>     immutable int value = 42;
>>     int[] y;
>>     y ~= getValue2(value); // No error
>>     return &y[0];
>> }
>>
>> void main()
>> {
>>     auto p = foo2();
>>     import std.stdio;
>>     writeln(*ip); /* Prints "42". */
>>     writeln(*ip); /* Prints garbage. An immutable value has changed. */
>> }
>> ----
> 
> Interestingly, taking the address of a `ref` in `@safe` code is prevented, but only when compiling *without* -preview=dip1000. See https://run.dlang.io/is/GArFzk
> 
> That's seems like a bug to me.

With DIP1000 enabled the compiler can figure out that it is safe to take the address of `i` and assign it to `my_ip`. It seems to fail to recognize that assigning to `ip` is unsafe. Perhaps that requires data flow analysis.

If you assign directly to `ip` it fails to compile.

-- 
/Jacob Carlborg