Bug 15805 – Automatic fix two erroneous integer comparison cases by widening
Status
RESOLVED
Resolution
WONTFIX
Severity
enhancement
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2016-03-17T12:49:00Z
Last change time
2016-04-11T06:58:06Z
Assigned to
nobody
Creator
b2.temp
Comments
Comment #0 by b2.temp — 2016-03-17T12:49:35Z
The front end could automatically fix two cases where comparing two integers gives in wrong results.
The trick is to widen the unsigned argument in a signed value, for example
int a = -1;
uint b;
if (a > b) {}
"b" can be widened in a long, which fixes the comaprison results.
POC in a simple template:
import std.traits;
bool safeIntegralCmp(string op, L, R)(auto ref L lhs, auto ref R rhs)
if (isIntegral!R && isIntegral!L)
{
// safe
static if (is(Unqual!L == Unqual!R))
{
mixin("return lhs" ~ op ~ "rhs;");
}
else
{
// promote unsigned to bigger signed
static if (isSigned!L && !isSigned!R && R.sizeof < 8)
{
long widenedRhs = rhs;
mixin("return lhs" ~ op ~ "widenedRhs;");
}
else static if (isSigned!R && !isSigned!L && L.sizeof < 8)
{
long widenedLhs = lhs;
mixin("return widened" ~ op ~ "rhs;");
}
// not fixable by operand widening
else
{
pragma(msg, "warning, comparing a" ~ L.stringof ~ " with a" ~ R.stringof
~ " may result into wrong results");
mixin("return lhs" ~ op ~ "rhs;");
}
}
}
unittest
{
int a = -1; uint b;
assert(a > b); // wrong result
assert(safeIntegralCmp!">"(a,b) == false); // fixed by promotion
long aa = -1; ulong bb;
assert(aa > bb); // wrong result
assert(safeIntegralCmp!">"(aa,bb) == true); // not staticaly fixable, warning
}
The widening that happends in the CT branches
* static if (isSigned!L && !isSigned!R && R.sizeof < 8)
* static if (isSigned!R && !isSigned!L && L.sizeof < 8)
could be done in the compiler.