Thread overview
Possible bug in RVO?
Apr 04, 2016
Yuxuan Shui
Apr 04, 2016
Yuxuan Shui
Apr 04, 2016
Yuxuan Shui
Apr 04, 2016
Yuxuan Shui
Apr 04, 2016
Anonymouse
Apr 04, 2016
Ali Çehreli
Apr 05, 2016
Yuxuan Shui
April 04, 2016
I have encountered a weird bug.

I defined a Set class, which has a opBinary!"-". And somehow this:

auto tmp = set_a-set_b;

produces different results as this:

set_a = set_a-set_b;

the latter will produce an empty set.

I tried to reduce the source code to get a test case. But this problem just goes away after removing some code.

Any ideas what I could have done wrong?
April 04, 2016
On Monday, 4 April 2016 at 03:28:01 UTC, Yuxuan Shui wrote:
> I have encountered a weird bug.
>
> I defined a Set class, which has a opBinary!"-". And somehow this:
>
> auto tmp = set_a-set_b;
>
> produces different results as this:
>
> set_a = set_a-set_b;
>
> the latter will produce an empty set.
>
> I tried to reduce the source code to get a test case. But this problem just goes away after removing some code.
>
> Any ideas what I could have done wrong?

OK, I think I got a test case:

import std.traits;
struct Set {
public:
	void insert(ulong v) {
		aa[v] = true;
	}
	size_t size() const {
		return aa.length;
	}
	auto opBinary(string op)(ref Set o) const {
		Set ret;
		foreach(k; aa.byKey)
			if (k !in o.aa)
				ret.insert(k);
		return ret;
	}
	@disable this(this);
	bool[ulong] aa;
}

struct XX {
	Set a, b, tmp;
	this(int n) {
		a.insert(n);
		tmp = a-b;
		a = a-b;
	}
}
void main(){
	import std.stdio;
	XX xx = XX(1000);
	writeln(xx.a.size);
	writeln(xx.tmp.size);
}

This does not happen when 'a' is on stack, that's why I was having trouble reproducing it.

I don't think this is valid code, because Set has disabled post-blit, 'a = a-b' should report an error. However, I don't think current behavior of dmd is correct either.
April 04, 2016
On Monday, 4 April 2016 at 03:28:01 UTC, Yuxuan Shui wrote:
> I have encountered a weird bug.
>
> I defined a Set class, which has a opBinary!"-". And somehow this:
>
> auto tmp = set_a-set_b;
>
> produces different results as this:
>
> set_a = set_a-set_b;
>
> the latter will produce an empty set.
>
> I tried to reduce the source code to get a test case. But this problem just goes away after removing some code.
>
> Any ideas what I could have done wrong?

A slightly more reduced test case:

struct Set {
	void insert(ulong v) {
		aa[v] = true;
	}
	@disable this(this);
	bool[ulong] aa;
}
auto clobber(ref Set x, ref Set o) {
	Set ret;
	ret.aa = x.aa;
	return ret;
}
struct XX {
	Set a, b, tmp;
	this(int n) {
		a.insert(1);
		//a.aa[1] = true;  <--- Swap above line with this doesn't trigger the bug
		tmp = a.clobber(b);
		a = a.clobber(b);
	}
}
void main(){
	import std.stdio;
	XX xx = XX(0);
	writeln(xx.a.aa.length);
	writeln(xx.tmp.aa.length);
}
April 04, 2016
On Monday, 4 April 2016 at 03:55:26 UTC, Yuxuan Shui wrote:
> On Monday, 4 April 2016 at 03:28:01 UTC, Yuxuan Shui wrote:
>> I have encountered a weird bug.
>>
>> I defined a Set class, which has a opBinary!"-". And somehow this:
>>
>> auto tmp = set_a-set_b;
>>
>> produces different results as this:
>>
>> set_a = set_a-set_b;
>>
>> the latter will produce an empty set.
>>
>> I tried to reduce the source code to get a test case. But this problem just goes away after removing some code.
>>
>> Any ideas what I could have done wrong?
>
> A slightly more reduced test case:
>

And LDC has the same problem with the first test case, but not with the second one.


April 04, 2016
On Monday, 4 April 2016 at 03:55:26 UTC, Yuxuan Shui wrote:
> On Monday, 4 April 2016 at 03:28:01 UTC, Yuxuan Shui wrote:
> auto clobber(ref Set x, ref Set o) {
> 	Set ret;
> 	ret.aa = x.aa;
 	  assert(x.aa.length > 0);  // <-- boom
> 	return ret;
> }

No idea myself but that's where it seems to go wrong.
April 04, 2016
On 04/04/2016 09:36 AM, Anonymouse wrote:
> On Monday, 4 April 2016 at 03:55:26 UTC, Yuxuan Shui wrote:
>> On Monday, 4 April 2016 at 03:28:01 UTC, Yuxuan Shui wrote:
>> auto clobber(ref Set x, ref Set o) {
>>     Set ret;
>>     ret.aa = x.aa;
>         assert(x.aa.length > 0);  // <-- boom
>>     return ret;
>> }
>
> No idea myself but that's where it seems to go wrong.

Looks like a bug. Just to make it more visible:

auto clobber(ref Set x, ref Set o) {
    writefln("entered clobber    - x.aa: %s", x.aa);
    Set ret;
    writefln("did not touch x.aa - x.aa: %s", x.aa);
    ret.aa = x.aa;
    return ret;
}

x.aa changes during the second call:

entered clobber    - x.aa: [1:true]
did not touch x.aa - x.aa: [1:true]
entered clobber    - x.aa: [1:true]
did not touch x.aa - x.aa: []          <-- What happened?

Ali

April 05, 2016
On Monday, 4 April 2016 at 21:31:08 UTC, Ali Çehreli wrote:
> On 04/04/2016 09:36 AM, Anonymouse wrote:
>> On Monday, 4 April 2016 at 03:55:26 UTC, Yuxuan Shui wrote:
>>>     [...]
>>         assert(x.aa.length > 0);  // <-- boom
>>> [...]
>>
>> No idea myself but that's where it seems to go wrong.
>
> Looks like a bug. Just to make it more visible:
>
> auto clobber(ref Set x, ref Set o) {
>     writefln("entered clobber    - x.aa: %s", x.aa);
>     Set ret;
>     writefln("did not touch x.aa - x.aa: %s", x.aa);
>     ret.aa = x.aa;
>     return ret;
> }
>
> x.aa changes during the second call:
>
> entered clobber    - x.aa: [1:true]
> did not touch x.aa - x.aa: [1:true]
> entered clobber    - x.aa: [1:true]
> did not touch x.aa - x.aa: []          <-- What happened?
>
> Ali

I filed an bug report here: https://issues.dlang.org/show_bug.cgi?id=15869