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.