[Issue 19183] DIP1000 defeated if auto used instead of scope in variable declaration with template this member function

d-bugmail at puremagic.com d-bugmail at puremagic.com
Thu Aug 23 11:29:39 UTC 2018


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

--- Comment #15 from ag0aep6g <ag0aep6g at gmail.com> ---
(In reply to Atila Neves from comment #13)
> > Apparently, DMD goes with infinite
> 
> Only if it's a template this function.

No. My statement was about the lifetime of `malloc(...)`, which is called in
the constructor. The constructor doesn't have a template this parameter.

Your code has a template this parameter on the method `ptr`. But before `ptr`
comes into play, the lifetime of the field has already been set to infinite.

If we initialize the field to something with restricted lifetime, then leaking
`s.ptr` gets rejected as it should be:

----
const(int)* gInts;
void main() @safe
{
    int x;
    auto s = MyStruct(&x);
    gInts = s.ptr; /* Error: scope variable s assigned to gInts with longer
lifetime */
}
struct MyStruct
{
    int* ints;
    scope ptr(this This)() { return ints; }
}
----

The problem is that `ints` starts out with infinite lifetime when it's
initialized with a `malloc` call. `ptr` just passes the wrong lifetime on.

Also, if anything, it's the inference of the `return` attribute that's the
problem. The template this parameter merely triggers that. Empty template
parentheses or an `auto` return type have the same effect.


> As mentioned before, writing out the
> explicit instantitations for mutable, const and immutable doesn't compile.
[...]
> dmd is already doing the right thing with `scope ptr() { return ints; }`,
> `scope ptr() const { return ints; }` and `scope ptr() immutable { return
> ints; }` even if it's `auto s = MyStruct(10)` instead of `scope s =
> MyStruct(10)`.

As mentioned before, I can't reproduce this. Please post complete code.

With those definitions for `ptr` I get this code:

----
@safe:

const(int)* gInts;

void main() {
    auto s = MyStruct(10);
    gInts = s.ptr;
}

struct MyStruct
{
    import core.stdc.stdlib;
    int* ints;
    this(int size) @trusted { ints = cast(int*) malloc(size); }
    ~this() { () @trusted { free(ints); }(); }

    scope ptr() { return ints; }
    scope ptr() const { return ints; }
    scope ptr() immutable { return ints; }
}
----

And that compiles just fine. Because the `return` attribute is still inferred.


> It's only if `ptr` is a template this function this bug manifests. There's
> also a bug with `inout`, but that's another issue:
> 
> https://issues.dlang.org/show_bug.cgi?id=17927

Yes, that's another issue. The method there doesn't have the `return`
attribute.

Maybe your point is that the `return` attribute shouldn't be inferred? Then
`ptr` wouldn't compile, but you could still make essentially the same mistake
by accessing `s.ints` directly.


> I didn't bother to respond to the rest of your analysis. The crux of the
> problem here is the interaction of a template function with DIP1000 and
> inferred lifetimes, and how it differs from the non-template functions.

My point is that changing the lifetime of `malloc(...)` could maybe fix this
issue and prevent the very similar mistake of copying `s.ints`, while still
allowing the `return` attribute to be inferred.

--


More information about the Digitalmars-d-bugs mailing list