Bug 17456 – [REG2.075a] spurious lifetime diagnostic on delegates
Status
RESOLVED
Resolution
INVALID
Severity
regression
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2017-05-30T18:03:00Z
Last change time
2017-05-30T22:20:04Z
Assigned to
nobody
Creator
b2.temp
Comments
Comment #0 by b2.temp — 2017-05-30T18:03:30Z
repro:
===
struct Foo
{
private void delegate() dg;
void assign() @safe {dg = &sameThis;}
void sameThis(){}
}
===
yield: "address of variable this assigned to this with longer lifetime"
But the delegate is never escaped and the context pointer and the this have the same lifetime.
Comment #1 by b2.temp — 2017-05-30T18:06:02Z
(In reply to b2.temp from comment #0)
> repro:
>
>
> ===
> struct Foo
> {
> private void delegate() dg;
> void assign() @safe {dg = &sameThis;}
> void sameThis(){}
> }
> ===
>
> yield: "address of variable this assigned to this with longer lifetime"
>
> But the delegate is never escaped and the context pointer and the this have
> the same lifetime.
In the project, the equivalent of "sameThis" is @trusted, in case of another error would appear.
Comment #2 by ag0aep6g — 2017-05-30T18:44:43Z
(In reply to b2.temp from comment #0)
> struct Foo
> {
> private void delegate() dg;
> void assign() @safe {dg = &sameThis;}
> void sameThis(){}
> }
> ===
>
> yield: "address of variable this assigned to this with longer lifetime"
As far as I see, the code is unsafe. Call `assign` on a Foo, then copy the Foo. The context pointer of the new dg will refer to the old Foo. Let the old Foo go out of scope. The context pointer now points to garbage.
I'm closing as invalid. Just reopen if I'm missing something.
In code:
----
struct Foo
{
int x;
private void delegate() dg;
void assign() /*@safe*/ {dg = &sameThis;}
void sameThis() { import std.stdio; writeln(x); }
}
void f(ref Foo dst)
/* ref parameter instead of return value, because dmd is smart
enough to avoid the copy when returning. */
{
Foo foo;
foo.x = 42;
foo.assign();
dst = foo;
}
void main()
{
Foo foo;
f(foo);
(){ int[100] stomp = 13; }();
foo.dg(); /* prints garbage (here: contents of 'stomp') */
}
----
Comment #3 by b2.temp — 2017-05-30T19:34:35Z
(In reply to ag0aep6g from comment #2)
> (In reply to b2.temp from comment #0)
> > struct Foo
> > {
> > private void delegate() dg;
> > void assign() @safe {dg = &sameThis;}
> > void sameThis(){}
> > }
> > ===
> >
> > yield: "address of variable this assigned to this with longer lifetime"
>
> As far as I see, the code is unsafe. Call `assign` on a Foo, then copy the
> Foo. The context pointer of the new dg will refer to the old Foo. Let the
> old Foo go out of scope. The context pointer now points to garbage.
>
> I'm closing as invalid. Just reopen if I'm missing something.
>
> In code:
>
> ----
> struct Foo
> {
> int x;
> private void delegate() dg;
> void assign() /*@safe*/ {dg = &sameThis;}
> void sameThis() { import std.stdio; writeln(x); }
> }
>
> void f(ref Foo dst)
> /* ref parameter instead of return value, because dmd is smart
> enough to avoid the copy when returning. */
> {
> Foo foo;
> foo.x = 42;
> foo.assign();
> dst = foo;
> }
>
> void main()
> {
> Foo foo;
> f(foo);
> (){ int[100] stomp = 13; }();
> foo.dg(); /* prints garbage (here: contents of 'stomp') */
> }
> ----
Of course, this is a struct.
Now what if i add
@disable this(this);
@disable void opAssign(Foo);
And everything that disable value move ?
It seems that the error is still emitted, right ?
Comment #4 by dlang-bugzilla — 2017-05-30T22:20:04Z
(In reply to b2.temp from comment #3)
> Now what if i add
>
> @disable this(this);
> @disable void opAssign(Foo);
>
> And everything that disable value move ?
> It seems that the error is still emitted, right ?
move and swap (from std.algorithm.mutation) will still work with such a struct.