Bug 18927 – Regression: Number with real suffix "L" sometimes fails to compile
Status
RESOLVED
Resolution
INVALID
Severity
minor
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Mac OS X
Creation time
2018-05-31T11:37:46Z
Last change time
2018-05-31T13:38:21Z
Assigned to
No Owner
Creator
Sophie
Comments
Comment #0 by meapineapple — 2018-05-31T11:37:46Z
I have a unit test that looks like this:
https://github.com/pineapplemachine/mach.d/blob/master/mach/text/numeric/floats.d#L482
unittest{ /// Parse float
alias numbers = Aliases!(
"0.0", "0.0000", "000.0000000000000000000000000",
"0.25", "0.025", "0.0005", "0.00000000000000005",
"1", "1.0", "10", "10.0", "11", "11.1", "11.11", "1111.111111111111111",
"2", "20", "200", "20000001", "123456", "123.456", "789.123456",
"1e0", "1e1", "1e2", "1e3", "1e4", "1e5", "1e100", "1e200", "1e2000",
"1e+0", "1e+1", "1e+2", "1e+3", "1e+4", "1e+5", "1e+100", "1e+200", "1e+2000",
"1e-0", "1e-1", "1e-2", "1e-3", "1e-4", "1e-5", "1e-100", "1e-200", "1e-2000",
"2e2", "123e4", "123456e7", "1.12313241e12", "1.1e-100", "111.111111111111e-100",
"1e01", "01e01", ".01", ".0002"
);
foreach(numberstr; numbers){
// Reals not included here because compiler and implementation output
// occassionally differ, and which output is more accurate varies.
foreach(T; Aliases!(double, float)){
mixin(`T a = ` ~ numberstr ~ `L;`);
mixin(`T b = -` ~ numberstr ~ `L;`);
immutable parseda = parsefloat!T(numberstr);
immutable parsedb = parsefloat!T(`+` ~ numberstr);
immutable parsedc = parsefloat!T(`-` ~ numberstr);
assert(fidentical(parseda, a));
assert(fidentical(parsedb, a));
assert(fidentical(parsedc, b));
}
}
}
The test compiled and passed with DMD 0.072.0. I switched to dmd-master-2018-05-28 and I got this compile error:
/Users/pineapple/Dropbox/Projects/mach.d/mach/text/numeric/floats.d-mixin-498(498): Error: cannot implicitly convert expression 20000001L of type long to float
/Users/pineapple/Dropbox/Projects/mach.d/mach/text/numeric/floats.d-mixin-499(499): Error: cannot implicitly convert expression -20000001L of type long to float
I have not been able to make a smaller repro case. This example program, for example, compiles without error and prints the expected value:
import std.stdio;
unittest{
alias T = double;
double n = 20000001L;
writeln(n);
}
Comment #1 by meapineapple — 2018-05-31T11:41:08Z
Ok, this code does not compile either:
/Users/pineapple/Dropbox/Projects/d/mobile-td/test.d(4): Error: cannot implicitly convert expression 20000001L of type long to float
import std.stdio;
unittest{
alias T = float;
T a = 20000001L;
writeln(a);
}
This workaround does compile:
import std.stdio;
unittest{
alias T = float;
T a = 20000001.0L;
writeln(a);
}
This code also compiles:
import std.stdio;
unittest{
alias T = float;
T a = 100L;
writeln(a);
}
Comment #2 by simen.kjaras — 2018-05-31T12:07:06Z
Beyond 16777216, not all integers are representable in a float, and 9007199254740992L is the same threshold for a double. This is because of how the floating-point formats are designed, and not a language issue. Previous behavior loses information and is bug prone, and a failure to compile gives immediate feedback that the programmer is doing something wrong, and does not generate invalid code.
For workarounds, T n = cast(T)20_000_001; works, as does 20_000_001.0, as you've pointed out.
This test shows the actual limits:
unittest{
static assert( __traits(compiles, { float a = 16777216; }));
static assert(!__traits(compiles, { float b = 16777217; }));
static assert( __traits(compiles, { double d = 9007199254740992L; }));
static assert(!__traits(compiles, { double d = 9007199254740993L; }));
}
Comment #3 by meapineapple — 2018-05-31T12:41:07Z
L is supposed to also be a suffix for reals, not only for long integers.
Comment #4 by kinke — 2018-05-31T13:38:21Z
(In reply to Sophie from comment #3)
> L is supposed to also be a suffix for reals, not only for long integers.
It's not just supposed to, it is. To dinstinguish between `long` and `real` literals, the latter needs a '.' or an exponent, analogous to `int` vs. `double` literals.