[Issue 22027] New: inout shouldn't imply return

d-bugmail at puremagic.com d-bugmail at puremagic.com
Tue Jun 15 23:22:27 UTC 2021


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

          Issue ID: 22027
           Summary: inout shouldn't imply return
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Keywords: safe
          Severity: enhancement
          Priority: P1
         Component: dmd
          Assignee: nobody at puremagic.com
          Reporter: dkorpel at live.nl

Currently `inout` parameters imply the `return` attribute. It's a special case,
adding complexity to the language and the compiler, and it doesn't make sense.
The rationale of it is:

> The idea is that the inout doesn't make sense if one is not returning 
> something based on the parameter marked with inout.
https://github.com/dlang/dmd/pull/10390#issuecomment-528774351

However, as pointed out by Rainer Schuetze, it's possible to return something
else that has the same qualifier as the parameter but different lifetime.

```
struct Large { void[4000] data; }
struct SImpl
{
   Large d;
}
struct S
{
   SImpl* impl; // GC managed?
   ref inout(Large) getLarge() inout { return impl.d; }
}

```
https://github.com/dlang/dmd/pull/10390#issuecomment-529177731

In fact, here are examples of valid uses of inout with every combination of
ref/return/scope, showing that it doesn't ever imply the need for `return`:
```
struct Node
{
    int x;
    Node* next;
    inout(int*) next_v0() return       inout {return &this.x;}
    inout(int*) next_v1() return scope inout {return &this.next.x;}
    inout(int*) next_v2()        scope inout {return &this.next.next.x;}
    inout(int*) next_v3()              inout {return &this.next.x;}

    ref inout(int) next_r0() return       inout {return this.next.x;}
    ref inout(int) next_r1()        scope inout {return this.next.next.x;}
    ref inout(int) next_r2() return scope inout {return this.next.next.x;}
    ref inout(int) next_r3()              inout {return this.next.x;}
}

inout(int*) next_v0(return       inout Node this_) {return &this_.next.x;}
inout(int*) next_v1(return scope inout Node this_) {return &this_.next.x;}
inout(int*) next_v2(       scope inout Node this_) {return &this_.next.next.x;}
inout(int*) next_v3(             inout Node this_) {return &this_.next.x;}

ref inout(int) next_r0(return       inout Node this_) {return this_.next.x;}
ref inout(int) next_r1(return scope inout Node this_) {return this_.next.x;}
ref inout(int) next_r2(       scope inout Node this_) {return
this_.next.next.x;}
ref inout(int) next_r3(             inout Node this_) {return this_.next.x;}
```

It's also worth noting that the current implementation has a bug that's
trivially fixed by removing the special case:
https://issues.dlang.org/show_bug.cgi?id=20149

```
@safe:   
struct ScopeBuffer {
    char[4] buf;
    inout(char)[] getSlice() inout {return buf[];}
}

char[] fun() {
    char[4] buf = "abcd";
    ScopeBuffer sb = ScopeBuffer(buf);
    return sb.getSlice; // dangling slice to stack memory is returned here
}

void main() {
    auto s = fun();
}
```

--


More information about the Digitalmars-d-bugs mailing list