Comment #0 by moonlightsentinel — 2021-04-27T09:34:21Z
Reduced example from TempCString in Phobos:
=======================================================================
char* foo(string s) @safe
{
// Previously used via `alias this`
char* p = tempCString(s).ptr;
// Also works
TempCStringBuffer res;
p = res.ptr;
return p;
}
TempCStringBuffer tempCString(scope string str) @safe;
struct TempCStringBuffer
{
char* ptr() return scope @safe
{
return &_buff[0];
}
private:
char* _ptr; // <= Required
char[256] _buff;
}
=======================================================================
Note that DMD reports the correct error when the unused `_ptr` is absent.
Comment #1 by dkorpel — 2021-06-03T18:46:15Z
Here's it reduced some more:
```
struct S {
int buf;
int* ptr; // <= required
}
int* getPtr(ref return scope S this_) {
return &this_.buf;
}
```
Since getPtr does not return by `ref`, the `return scope` applies to the members of `S` and not the `ref this_` itself.
The compiler checks whether `&this_.buf;` is escaped by value.
In `visit(AddrExp e)` of escape.d, it reduces this to checking whether `this_.x` escapes by ref, which reduces to checking whether `this_` escapes by ref.
Then it looks at the parameter's storage classes, and sees `return`, so it allows it.
This is wrong, the `return` does not apply to `&this_.x`, only to `this_.buf`;
Without the `buf` member, S has no pointers, so the `return scope` attribute is meaningless, so it is stripped away at some earlier stage.
This way the compiler can't mistake it for a `ref return`, so it raises an error.
I'm still trying to grasp the incredibly difficult logic in escape.d so I'm not sure how to fix this yet.
Comment #2 by dkorpel — 2021-06-03T18:48:42Z
> This is wrong, the `return` does not apply to `&this_.x`, only to `this_.buf`;
I should be careful when renaming variables :) Corrections:
* reduces this to checking whether `this_.buf` escapes by ref
* This is wrong, the `return` does not apply to `&this_.buf`, only to `this_.ptr`;
Comment #3 by dlang-bot — 2021-06-10T14:58:30Z
@dkorpel created dlang/dmd pull request #12665 "Fix issue 21868 - conflation of return-ref and return-scope" fixing this issue:
- fix issue 21868 - conflation of return-ref and return-scope
https://github.com/dlang/dmd/pull/12665
Comment #4 by dkorpel — 2021-06-10T19:22:40Z
*** Issue 18792 has been marked as a duplicate of this issue. ***
Comment #5 by bugzilla — 2021-07-06T07:32:46Z
Minimized test case:
ref int test(ref scope return int* p)
{
return *p;
}
Comment #6 by dlang-bot — 2021-07-06T08:02:19Z
@WalterBright created dlang/dmd pull request #12817 "fix Issue 21868 - DIP1000 doesn't catch pointer to struct temporary" fixing this issue:
- fix Issue 21868 - DIP1000 doesn't catch pointer to struct temporary
https://github.com/dlang/dmd/pull/12817
Comment #7 by bugzilla — 2021-07-07T01:44:55Z
(In reply to Walter Bright from comment #5)
> Minimized test case:
>
> ref int test(ref scope return int* p)
> {
> return *p;
> }
This is a separate bug, so moved to:
https://issues.dlang.org/show_bug.cgi?id=22108
Comment #8 by dlang-bot — 2021-07-07T10:31:25Z
@WalterBright created dlang/dmd pull request #12829 "fix Issue 21868 - DIP1000 does not catch pointer to struct temporary" fixing this issue:
- fix Issue 21868 - DIP1000 does not catch pointer to struct temporary
https://github.com/dlang/dmd/pull/12829
Comment #9 by dlang-bot — 2021-07-23T13:39:00Z
dlang/dmd pull request #12829 "fix Issue 21868 - DIP1000 does not catch pointer to struct temporary" was merged into master:
- f05f600c66edb966fa63d54653f3c3d280cfda8e by Walter Bright:
fix Issue 21868 - DIP1000 does not catch pointer to struct temporary
https://github.com/dlang/dmd/pull/12829