Bug 7353 – NRVO not properly working with inferred return type

Status
RESOLVED
Resolution
FIXED
Severity
critical
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2012-01-23T07:27:00Z
Last change time
2012-02-17T19:33:33Z
Keywords
performance, pull
Assigned to
nobody
Creator
hoganmeier

Comments

Comment #0 by hoganmeier — 2012-01-23T07:27:36Z
import std.stdio; struct S { static uint ci = 0; uint i; this(int x) { i = ci++; writeln("new: ", i); } this(this) { i = ci++; writeln("copy ", i); } ~this() { writeln("del ", i); } S save1() // produces 2 copies in total { S s = this; return s; } auto save2() // produces 3 copies in total { S s = this; return s; pragma(msg, typeof(return)); } S save3() { return this; } } void main() { { S s = S(1); S t = S(1); t = s.save1(); } writeln("-"); S.ci = 0; { S s = S(1); S t = S(1); t = s.save2(); } writeln("-"); S.ci = 0; { S s = S(1); S t = S(1); t = s.save3(); } } $ dmd -run test.d //or dmd -release -run test.d //or dmd -release -O -run test.d S new: 0 new: 1 copy 2 del 1 del 2 del 0 - new: 0 new: 1 copy 2 copy 3 del 2 del 1 del 3 del 0 - new: 0 new: 1 copy 2 del 1 del 2 del 0 $ dmd -release -O -inline -run test.d S new: 0 new: 1 copy 2 del 1 del 2 del 0 - new: 0 new: 1 copy 2 copy 3 del 2 del 1 del 3 del 0 - new: 0 new: 1 del 1 del 0 del 0
Comment #1 by hoganmeier — 2012-01-23T07:32:24Z
Hmm that last one even looks like a wrong-code bug, 0 is deleted twice.
Comment #2 by k.hara.pg — 2012-02-15T06:39:48Z
Postblit is only in D2 spec, so this is not 'D1 & d2' issue. I think save3() is inlining problem, then I've separated it as bug 7506. Therefore I remove 'wrong-code' keyword. ---- Current compiler implementation disables nrvo with auto function. I've post a pull to fix it. https://github.com/D-Programming-Language/dmd/pull/722
Comment #3 by hoganmeier — 2012-02-15T08:48:44Z
You're right. The third one is an inlining problem. But there's a different thing I'm now confused about. Why is postblit called after all? It's assignment to t, not construction. See the docs: struct S { ... } S s; // default construction of s S t = s; // t is copy-constructed from s => this(this) t = s; // t is assigned from s => opAssign
Comment #4 by k.hara.pg — 2012-02-15T09:16:26Z
(In reply to comment #3) > You're right. The third one is an inlining problem. > > But there's a different thing I'm now confused about. Why is postblit called > after all? > It's assignment to t, not construction. > > See the docs: > struct S { ... } > S s; // default construction of s > S t = s; // t is copy-constructed from s => this(this) > t = s; // t is assigned from s => opAssign The assignment to t does not call postblit. Because the built-in opAssign is implemented as 'swap and destroy' due to never create any unnecessary copy on assignment. First of all, S has postblit, then dmd creates implicit built-in opAssing like follows: ref S opAssign(S rhs) { // rhs receives rvalue, not lvalue swap(this, rhs); return this; // rhs is destroyed the end of opAssign function scope } Next, the code sequence with explanation: { S s = S(1); // prints new: 0 S t = S(1); // prints new: 1 t = s.save1(); // is translated to t.opAssign(s.save1()) // inside save1(): S s = this; // prints copy 2 return s; // s is moved out by nrvo // t.opAssign receives moved value, so is never copied // inside t.opAssign(): // this (this.i==1) is swapped with rhs, and destroyed // prints del 1 // s.i == 0 // t.i == 2 // destroyed local variables in reverse order // prints del 2 // prints el 1 } Last, the postblit call runs only once.
Comment #5 by hoganmeier — 2012-02-15T11:39:08Z
Ok, so in essence the postblit is the one called by 'S s = this;' in save1. But what about save3?
Comment #6 by github-bugzilla — 2012-02-17T18:21:35Z
Commit pushed to master at https://github.com/D-Programming-Language/dmd https://github.com/D-Programming-Language/dmd/commit/02ecef1cea5dea4f78bafb7533c896d0d9b07816 Merge pull request #722 from 9rnsr/fix7353 Issue 7353 - NRVO not properly working with inferred return type