Comment #0 by pro.mathias.lang — 2020-04-20T02:08:44Z
Since half of the logic for NRVO is in the backend, this traits simply cannot be relied on and is mostly useless.
For example, the following compiles and triggers the assert with DMD:
```
import std.meta;
import std.traits;
import std.stdio;
T deserializeFull (T) (scope ubyte[] delegate(size_t) dg)
{
static if (is(T == ulong))
{
ulong ret = *cast(ulong*)(dg(ulong.sizeof).ptr);
return ret;
}
else static if (is(T == ulong*))
{
return null;
}
else static if (is(T == struct))
{
Target convert (Target) ()
{
auto x = deserializeFull!Target(dg);
return x;
}
auto enableNRVO = T(staticMap!(convert, Fields!T));
return enableNRVO;
}
else
static assert(0);
}
struct FooBar
{
this(Repeat!(6, ulong) vals, ulong* ignored)
{
this.tupleof[0 .. vals.length] = vals;
this.ptr = &this.a;
}
ulong a;
ulong b;
ulong c;
ulong d;
ulong e;
ulong f;
ulong* ptr;
}
struct WrapMe { FooBar fb; FooBar xc; }
void main ()
{
//FooBar f;
ubyte[WrapMe.sizeof] binary = 42;
ubyte[] tmp = binary;
scope ubyte[] delegate(size_t v) getter = (v) {
scope(success) tmp = tmp[v .. $];
return tmp[0 .. v];
};
auto final_ = deserializeFull!WrapMe(getter);
writeln("ptr: ", final_.fb.ptr, " == ", &final_.fb.a);
assert(final_.fb.ptr is &final_.fb.a);
static assert(__traits(isReturnOnStack, deserializeFull!WrapMe));
}
```
LDC v1.20.1 compiles and run this just fine, but not DMD:
```
% dmd -run repro.d
ptr: 7FFEE998E3D8 == 7FFEE998E520
[email protected](61): Assertion failure
----------------
??:? _d_assertp [0x10628dcbd]
??:? _Dmain [0x10627192a]
```
I would expect a compilation error, or the assert to pass.
Comment #1 by ibuclaw — 2020-04-21T15:55:00Z
(In reply to Mathias LANG from comment #0)
> Since half of the logic for NRVO is in the backend, this traits simply
> cannot be relied on and is mostly useless.
For finding out if a struct is to be returned using (N)RVO, the right test to use would be __traits(isPOD).
If a struct is non-POD, then it should _always_ be passed around by invisible reference, no ifs, no buts, no excuses.
However, that's ignoring static arrays, which is a little more hairy to find out, as they need to be big enough to be considered returning in memory. But just what is "big enough" is a very target-specific question.
> For example, the following compiles and triggers the assert with DMD:
>
[--snip--]
>
> I would expect a compilation error, or the assert to pass.
Worse, some back-ends can't provide any useful information as there's no access to "target". This is from the gdc-ddmd branch with included explanation.
---
bool
Target::isReturnOnStack (TypeFunction *, bool)
{
/* Need the back-end type to determine this, but this is called from the
frontend before semantic processing is finished. An accurate value
is not currently needed anyway. */
return true;
}
---
A type could be synthesized, however. But it would be a best guess approach.
Comment #2 by kinke — 2020-04-21T17:51:44Z
(In reply to Iain Buclaw from comment #1)
> For finding out if a struct is to be returned using (N)RVO, the right test
> to use would be __traits(isPOD).
>
> If a struct is non-POD, then it should _always_ be passed around by
> invisible reference, no ifs, no buts, no excuses.
>
> However, that's ignoring static arrays, which is a little more hairy to find
> out, as they need to be big enough to be considered returning in memory.
> But just what is "big enough" is a very target-specific question.
That goes for large structs too, not just static arrays, so isPOD is definitely not sufficient.
The isReturnOnStack trait isn't directly related to NRVO and only depends on the ABI; in LLVM lingo, passing a pointer to the pre-allocated result is called sret, struct-return. NRVO just means that a named variable in the callee will be emplaced into that memory directly, so an sret ABI requirement for the callee is an orthogonal prerequisite for NRVO to work (in the callee).
Comment #3 by bugzilla — 2020-10-05T09:59:28Z
> the following compiles and triggers the assert with DMD:
A much smaller example would be nice. For example, all those templates seem an unnecessary complication.
Comment #4 by robert.schadek — 2024-12-13T19:08:12Z