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