| Thread overview | |||||||
|---|---|---|---|---|---|---|---|
|
April 08, 2013 Presence of struct destructor makes lvalue? | ||||
|---|---|---|---|---|
| ||||
The following program has two assignments from two rvalues:
import std.stdio;
import std.string;
// version = destructor_defined;
struct S
{
int i;
string info() const
{
return format("%s(%s)", &i, i);
}
void opAssign(S rhs)
{
writefln("%s from Rvalue %s", this.info(), rhs.info());
}
void opAssign(ref S rhs)
{
writefln("%s from Lvalue %s", this.info(), rhs.info());
}
version (destructor_defined)
{
~this()
{
writefln("destroying %s", this.info());
}
}
}
S foo(int i)
{
return S(i);
}
void main()
{
auto s = S(1);
// Assignment from two kinds of rvalues
s = foo(2);
s = S(3);
}
The output indicates that the two assignments go to the "rvalue assignment operator":
7FFF36AA0B20(1) from Rvalue 7FFF36AA0B24(2)
7FFF36AA0B20(1) from Rvalue 7FFF36AA0B28(3)
However, when S.~this() is defined (by e.g. uncommenting the 'version =' line), the second assignment involves an lvalue:
7FFF9571E7F8(1) from Rvalue 7FFF9571E750(2)
destroying 7FFF9571E750(2)
7FFF9571E7F8(1) from Lvalue 7FFF9571E804(3) <-- HERE
destroying 7FFF9571E804(3)
destroying 7FFF9571E7F8(1)
I suspect this has something to do with the compiler generated assignment logic:
http://dlang.org/struct.html
[quote]
Struct assignment t=s is defined to be semantically equivalent to:
t.opAssign(s);
where opAssign is a member function of S:
S* opAssign(ref const S s)
{ ... bitcopy *this into tmp ...
... bitcopy s into *this ...
... call destructor on tmp ...
return this;
}
[/quote]
It is not clear how the presence of ~this() changes the semantics. Bug?
Thank you,
Ali
| ||||
April 08, 2013 Re: Presence of struct destructor makes lvalue? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | DMD often inserts temporaries when they are unexpected (or users do not expect when they should). D main function in destructor case is rewritten as: S s = S(1); s.opAssign(foo(2)); s.opAssign((S __sl1779 = S(3); , __sl1779)) Hence, ref version is taken in account because '__sl1779' is a good lvalue. Troubles seems to come from https://github.com/D-Programming-Language/dmd/blob/master/src/expression.c#L4203 | |||
April 08, 2013 Re: Presence of struct destructor makes lvalue? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Maxim Fomin | On 04/08/2013 12:24 PM, Maxim Fomin wrote: > DMD often inserts temporaries when they are unexpected (or users do not > expect when they should). > > D main function in destructor case is rewritten as: > > S s = S(1); > s.opAssign(foo(2)); > s.opAssign((S __sl1779 = S(3); , __sl1779)) Have you manually typed those lines or is there a tool that outputs that "preprocessor" ;) output? > > Hence, ref version is taken in account because '__sl1779' is a good lvalue. > > Troubles seems to come from > https://github.com/D-Programming-Language/dmd/blob/master/src/expression.c#L4203 > Thank you very much for finding the related line. :) Quoting: Expression *StructLiteralExp::semantic(Scope *sc) { Expression *e; // ... /* If struct requires a destructor, rewrite as: * (S tmp = S()),tmp * so that the destructor can be hung on tmp. */ if (sd->dtor && sc->func) { Identifier *idtmp = Lexer::uniqueId("__sl"); VarDeclaration *tmp = new VarDeclaration(loc, type, idtmp, new ExpInitializer(0, this)); tmp->storage_class |= STCctfe; Expression *ae = new DeclarationExp(loc, tmp); Expression *e = new CommaExp(loc, ae, new VarExp(loc, tmp)); e = e->semantic(sc); return e; } return this; } Is it because destructors cannot be "hung" on literals? It is inconsistent that function-returned rvalues do not behave the same as literal-rvalues. Ali | |||
April 09, 2013 Re: Presence of struct destructor makes lvalue? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli Attachments:
| This is definitely a bug. http://d.puremagic.com/issues/show_bug.cgi?id=9907 Kenji Hara 2013/4/9 Ali Çehreli <acehreli@yahoo.com> > On 04/08/2013 12:24 PM, Maxim Fomin wrote: > > > DMD often inserts temporaries when they are unexpected (or users do not > > expect when they should). > > > > D main function in destructor case is rewritten as: > > > > S s = S(1); > > s.opAssign(foo(2)); > > s.opAssign((S __sl1779 = S(3); , __sl1779)) > > Have you manually typed those lines or is there a tool that outputs that "preprocessor" ;) output? > > > > > > Hence, ref version is taken in account because '__sl1779' is a good > lvalue. > > > > Troubles seems to come from https://github.com/D-**Programming-Language/dmd/blob/** > master/src/expression.c#L4203<https://github.com/D-Programming-Language/dmd/blob/master/src/expression.c#L4203> > > > > Thank you very much for finding the related line. :) Quoting: > > Expression *StructLiteralExp::semantic(**Scope *sc) > { Expression *e; > > // ... > > /* If struct requires a destructor, rewrite as: > * (S tmp = S()),tmp > * so that the destructor can be hung on tmp. > */ > if (sd->dtor && sc->func) > { > Identifier *idtmp = Lexer::uniqueId("__sl"); > VarDeclaration *tmp = new VarDeclaration(loc, type, idtmp, new > ExpInitializer(0, this)); > tmp->storage_class |= STCctfe; > Expression *ae = new DeclarationExp(loc, tmp); > Expression *e = new CommaExp(loc, ae, new VarExp(loc, tmp)); > e = e->semantic(sc); > return e; > } > > return this; > } > > Is it because destructors cannot be "hung" on literals? > > It is inconsistent that function-returned rvalues do not behave the same as literal-rvalues. > > Ali > > | |||
April 09, 2013 Re: Presence of struct destructor makes lvalue? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to kenji hara | On 04/08/2013 07:13 PM, kenji hara wrote:> This is definitely a bug. > > http://d.puremagic.com/issues/show_bug.cgi?id=9907 > > Kenji Hara Thank you! :) You've already fixed it! (Pending merge...) Ali | |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply