On Tuesday, 19 February 2013 at 10:16:47 UTC, monarch_dodra wrote:
On Monday, 18 February 2013 at 21:32:13 UTC, Zach the Mystic
wrote:
On Monday, 18 February 2013 at 11:10:38 UTC, monarch_dodra
wrote:
I think I'm opening a can of worms here, in regards to
inferring the escape of references, but a quick investigation
showed me that return by auto-ref is horribly broken.
Basically, the only thing it does is check if the very last
value it returns is a ref, but a ref to what? The
possibilities of returning a ref to a local are HUGE. For
example, simple returning the index of a tuple, or of a
static array, and you're in it deep:
//----
import std.typecons;
auto ref foo(T)(auto ref T t)
{
return t[0];
}
void main()
{
int* p = &foo(tuple(1, 2));
}
//----
Here, both foo will return a ref to a local. But the compiler
won't see, and more importantly, it gets blind sided because
it *can't* see it (AFAIK).
If you take the address of a value returning type, you must
either ban doing it outright or treat the assigned pointer as
dangerous. To take the address of a value type returned from
the stack is especially dangerous - I can see banning it
outright and I don't know what the spec currently says about
this.
What I wanted to show was that since the code compiled, foo
returned by ref. At this point, the assigned pointer shouldn't
even be considered as "dangerous", since we are already in
undefined behavior.
Well, "extra dangerous" then, undefined, and probably should be
detected and made illegal.
I could have replaced the code with:
"int a = foo(tuple(1, 2));"
The bug would have been less obvious, but there are chances
this creates a (very) hard to catch bug.
Well, my guess would be that this is actually safe, because a is
assigned by value here and not by reference. (Unless you're
saying that foo ends up smashing tuple(1,2)'s location, but yeah,
this is referring to a part of the stack which should be
considered 'void'.)
My assumption would be that the only legal version of this
would be the one which returns 'ref'. But tuple(1,2) is an
rvalue struct type if I'm not mistaken, which means it would
be passed as a value. The compiler should not allowed a type
passed as a value (or any part of that value) to be returned
as a reference, right? So I don't see a way to take the
address of this result legally. I don't think it should return
a reference at all with 'tuple(1,2)'. That's all I know.
Indeed, there is no way to take the address of the returned
value in this case, since it shouldn't return by ref.
But it does...
I will start by assuming it's a bug and not a problem with
language design. There are clear points at which it cannot be
justified to be considered legal, from my perspective. I'll file
it as a bug.
http://d.puremagic.com/issues/show_bug.cgi?id=9537
My guess is that 'foo' doesn't realize that 't[0]' is a reference
derived from a local parameter.