Seems to be a problem with using "each" under 32bit which can be fixed by using foreach or switching to x64.
Let to a long discussion on the learn forum that went past my pay grade: https://forum.dlang.org/post/[email protected]
Below is a silly case, that replicates the error. (i.e. I know I could use iota(0,9,2).array), but that does not demonstrate the potential bug and would not fix my actual program.)
import std.range;
import std.algorithm;
import std.stdio;
unittest
{
auto a = new double[9];
a[0] = 0;
iota(1,a.length).each!(i => a[i] = a[i-1] + 2);
writeln(a);
}
//x86, wrong, error
//[-nan, 2, 4, 6, 8, 10, 12, 14, 16]
//First-chance exception: std.format.FormatException Unterminated format specifier: "%" at C:\D\dmd2\windows\bin\..\..\src\phobos\std\format.d(1175)
//x64, correct
//[0, 2, 4, 6, 8, 10, 12, 14, 16]
unittest
{
auto a = new double[9];
a[0] = 0;
foreach(i; 1..a.length) a[i] = a[i - 1] + 2;
writeln(a);
}
//x86, correct
//[0, 2, 4, 6, 8, 10, 12, 14, 16]
//x64, correct
//[0, 2, 4, 6, 8, 10, 12, 14, 16]
Originally found on windows 10, DMD v2.076.1, but now confirmed by others on linux and current version.
Comment #1 by ketmar — 2018-03-07T22:05:11Z
some clarification: basically, this boils down to codegen bug: if we have function that returns some floating point value, and FPU is involved, and caller does `cast(void)myfunc()`, result is not popped from FPU stack.
note that `cast(void)` is vital here: everything is ok without it. also, as X86_64 doesn't use FPU for floats and doubled, you need to use `real` there to trigger the bug.
minified sample by ag0aep6g:
double f() { return 1; }
void main()
{
cast(void) f();
cast(void) f();
cast(void) f();
cast(void) f();
cast(void) f();
cast(void) f();
cast(void) f();
double b = 2;
assert(b == 2); /* fails; should pass */
}
Comment #2 by ketmar — 2018-03-07T22:06:52Z
p.s.: as this bug affects x86_64 too (albeit only with `real`s), i changed arch to all.
Comment #3 by ag0aep6g — 2019-02-14T20:54:05Z
*** Issue 19437 has been marked as a duplicate of this issue. ***
Comment #4 by bugzilla — 2019-02-14T23:13:31Z
The test case:
real foo();
void test1() {
cast(void)foo();
}
void test2() {
foo();
}
compiles to:
__D4test5test1FZv:
call __D4test3fooFZe
ret
__D4test5test2FZv:
call __D4test3fooFZe
fstp ST
ret
which nicely illustrates the problem.
dlang/dmd pull request #9362 "fix Issue 18573 - cast(void) leads to floating point return value not…" was merged:
https://github.com/dlang/dmd/pull/9362