June 09, 2022
On 09.06.22 14:45, Dennis wrote:
> On Thursday, 9 June 2022 at 00:38:13 UTC, Timon Gehr wrote:
>> ```d
>> int* foo()@system{
>>     int x;
>>     return &x; // error
>> }
>>
>> int* foo(ref int x)@system{
>>     return &x; // error
>> }
>>
>> int* foo(scope int* x)@system{
>>     return x; // ok
>> }
>> ```
>>
>> This does not have anything to do with `@safe` by default, it's just an inconsistency in the compiler implementation.
> 
> I noticed this as well, and as of https://github.com/dlang/dmd/pull/14107 the `&ref` escape is treated the same as returning a scope pointer (error in @safe code only). Returning &local directly is still an error in @system code, that error predates @safe and dip1000.

Well, not a big fan. This is the wrong way around.
June 09, 2022

On Thursday, 9 June 2022 at 13:00:01 UTC, Timon Gehr wrote:

>

Well, not a big fan. This is the wrong way around.

It was needed to avoid breaking existing code, which is sometimes annotated incorrectly because of compiler bugs and the return ref scope ambiguity issue. Once the dip1000 by default transition has progressed and people corrected the return ref / return scope annotations in their code, I think it can become an error in @system code again.

June 09, 2022

On Thursday, 9 June 2022 at 01:18:30 UTC, Steven Schveighoffer wrote:

>

For some reason, while you can't return a pointer to a local, you can return a scope pointer.

A pointer to a local is guaranteed to be a dangling pointer when you return it, while a scope pointer is not guaranteed to be memory with limited lifetime when you return it. scope is only a conservative compile-time approximation of what's actually happening, which makes it susceptible to false positives:

int* f(int x) @safe {
    int* p = &x; // p is inferred scope here
    p = new int; // p is no longer pointing to stack memory
    return p;    // Error: scope variable `p` may not be returned
}

This function could be permitted as @system or @trusted code.

June 09, 2022
On 09.06.22 08:53, Walter Bright wrote:
> The point of @safe by default for C declarations was:
> 
> 1. so that we would not be deluged with complaints about breaking existing code
> ...

It really does not help much with that. In addition, it would slap `@safe` on code that is not actually memory safe and was not intended to be. That's also breakage.

> 2. so people would use it
> 
> What people *will* do with C unsafe by default is:
> 
> 1. slap `@trusted:` at the beginning and go on their merry way,

This is not what I will do, but they can of course just do that. It's very visible in code review.

> and nothing was accomplished except annoying people

Your are predicting that some people will explicitly do the wrong and lazy thing, hence the compiler should do the wrong and lazy thing implicitly by default. This just makes no sense. What's the big harm in annoying lazy people slightly more? It's not like they won't complain loudly about `@safe` by default in any case. May as well do it right or not at all.
June 09, 2022
On Wednesday, 8 June 2022 at 19:21:56 UTC, rikki cattermole wrote:
>
> On 09/06/2022 7:18 AM, claptrap wrote:
>> Isn't the DIP process supposed to catch these sorts of things?
>
> DIP1000 was the first DIP to go through the new system. But even then, we are still having to change how it works many years after the fact due to the complexities involved.

Sorry I was being facetious...

DIP1000 : "This DIP did not complete the review process"

But we're getting it anyway....

Oh wait nobody seems to really understand it, even the gurus cant seem to agree how or how it should it work.

But we're getting it anyway....

Oh wait weird stuff is happening

But we're getting it anyway....

Not directed at you FWIW, its just a joke that the first DIP through the new "lets add more rigour to the process by which we add things to D" process, failed to pass, and yet we're getting it anyway.


June 09, 2022
On 09.06.22 16:46, Dennis wrote:
> On Thursday, 9 June 2022 at 01:18:30 UTC, Steven Schveighoffer wrote:
>> For some reason, while you can't return a pointer to a local, you can return a scope pointer.
> 
> A pointer to a local is guaranteed to be a dangling pointer when you return it, while a `scope` pointer is not guaranteed to be memory with limited lifetime when you return it. `scope` is only a conservative compile-time approximation of what's actually happening, which makes it susceptible to false positives:
> 
> ```D
> int* f(int x) @safe {
>      int* p = &x; // p is inferred scope here
>      p = new int; // p is no longer pointing to stack memory
>      return p;    // Error: scope variable `p` may not be returned
> }
> ```
> This function could be permitted as @system or @trusted code.

Sure, and it should be. But the example was this:

```d
int* foo(scope int* s){ return s; }
```

There is no upside to allowing this `scope` annotation.
June 09, 2022

On 6/9/22 10:46 AM, Dennis wrote:

>

On Thursday, 9 June 2022 at 01:18:30 UTC, Steven Schveighoffer wrote:

>

For some reason, while you can't return a pointer to a local, you can return a scope pointer.

A pointer to a local is guaranteed to be a dangling pointer when you return it, while a scope pointer is not guaranteed to be memory with limited lifetime when you return it. scope is only a conservative compile-time approximation of what's actually happening, which makes it susceptible to false positives:

int* f(int x) @safe {
     int* p = &x; // p is inferred scope here
     p = new int; // p is no longer pointing to stack memory
     return p;    // Error: scope variable `p` may not be returned
}

This function could be permitted as @system or @trusted code.

I want to stress that I'm actually OK with the current situation as far as returning scope pointers as not-scope pointers in @system code. I've returned &this quite a bit in my code.

What is not OK is the compiler turning actual requests for GC allocation into stack allocations based on that. At this point, it's a literal, but if it did this for e.g. new T, we are in for a lot of trouble.

I'll ask, is it undefined behavior to return a scope pointer as a non-scope pointer? If so, should we make UB so easy to do?

This obscure interaction between the attributes, and the weird relationship between the scopeness of the return value (you can't label the return value as scope, you have to instead label the parameter as return), paired with the odd choices the compiler makes, are going to lead to insanely hard-to-find memory corruption problems.

In any case, I filed a bugzilla issue: https://issues.dlang.org/show_bug.cgi?id=23175

-Steve

June 09, 2022
On Thursday, 9 June 2022 at 15:23:35 UTC, Timon Gehr wrote:
> [snip]
>
> Sure, and it should be. But the example was this:
>
> ```d
> int* foo(scope int* s){ return s; }
> ```
>
> There is no upside to allowing this `scope` annotation.

Am I right that the reason to only issue the error in @safe code that the compiler can only be 100% sure that it is scope is in @safe code?

What about making it so that in @system code it does the checks the best that it can? In other words, if the compiler can verify that you aren't using scope properly in @system code, then it gives an error as if it is @safe, but if it can't verify it then the current behavior with -preview=in occurs (I understand some risk of undefined behavior).

I suppose the problem with that is that the user may not know when the scope suddenly stops actually checking correctly in @system code. The other alternative would be that scope works regardless of @safe/@system code and fails to compile if the compiler can't verify it properly. That makes it a bit harder to use though, which I imagine is why they didn't go that way.
June 09, 2022

On Thursday, 9 June 2022 at 15:23:35 UTC, Timon Gehr wrote:

>

There is no upside to allowing this scope annotation.

You could call that function assumeNonScope and use it to bypass lifetime errors that are false positives.

June 09, 2022
On 6/9/22 20:46, Dennis wrote:
> On Thursday, 9 June 2022 at 15:23:35 UTC, Timon Gehr wrote:
>> There is no upside to allowing this `scope` annotation.
> 
> You could call that function `assumeNonScope` and use it to bypass lifetime errors that are false positives.

In exchange for apparently inviting UB. Not a great trade-off.