The following code was reduced from std.conv. It prints "BAD!!!" only with -O enabled. Since parse() gets rid of the entire contents of v, v.length should be zero upon exiting toImpl and nothing should be printed.
import core.stdc.stdio;
T toImpl(T)(immutable string value)
{
string v = value;
scope(exit)
{
if (v.length)
{
printf("BAD!!!");
}
}
return parse!T(v);
}
T parse(T)(ref string value)
{
value = value[0..0];
return 666;
}
void main()
{
immutable s = "42";
toImpl!float(s);
}
Comment #1 by clugdbug — 2012-11-15T05:29:59Z
Marginally reduced test case:
int bug6962(string value)
{
string v = value;
scope(exit)
assert(!v.length);
ref6962(v);
return 1;
}
void ref6962(ref string value)
{
value = value[0..0];
}
void main()
{
string s = "42";
bug6962(s);
}
Comment #2 by clugdbug — 2012-11-15T23:39:03Z
Further reduced. The 'ref' is not necessary. The return statement is required, otherwise the try-finally gets removed in the semantic pass.
void bug6962(string value)
{
string v = value;
try
{
v = v[0LU..0LU];
return;
}
finally
{
assert(!v.length);
}
}
void main()
{
bug6962("42");
}
---------
When compiled with -O, the assert is compiled incorrectly. Instead of taking v.length, it uses value.length.
Bonus: on Linux 64, running obj2asm on the object file (with or without -O) causes obj2asm to segfault.