Skip to content

Commit c95d1fb

Browse files
committed
Generalize WNEGCONSTCOMP to warn for all constants outside a type's range
1 parent 535e736 commit c95d1fb

File tree

7 files changed

+131
-51
lines changed

7 files changed

+131
-51
lines changed

RELEASENOTES-1.4.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,4 +312,7 @@
312312
- `release 6 6313`
313313
- `release 7 7026`
314314
- `note 6` The warning message for comparing a value of unsigned type to a negative constant has been improved to also warn for unsigned types shorter than 64 bits.
315-
- `release 6 6315`
315+
- `release 6 6315`
316+
- `note 6` Added warnings for comparing an integer to constant values
317+
outside the integer's range. E.g., given a variable `x` of type `uint8`,
318+
warnings will now be reported on expressions like `x >= 256` or `x == 3.14`.

py/dml/ctree.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1392,10 +1392,18 @@ def make(cls, site, lh, rh):
13921392
and lh.constant and rh.constant):
13931393
return mkBoolConstant(site, cls.eval_const(lh.value, rh.value))
13941394
if lhtype.is_int:
1395+
if rh.constant and rhtype.is_arith and (
1396+
cls.eval_const(lhtype.min(), rh.value)
1397+
== cls.eval_const(lhtype.max(), rh.value)):
1398+
report(WTYPELIMITS(site, rh, lhtype))
13951399
lh_maybe_negative = lhtype.signed
13961400
lh = as_int(lh)
13971401
lhtype = realtype(lh.ctype())
13981402
if rhtype.is_int:
1403+
if lh.constant and lhtype.is_arith and (
1404+
cls.eval_const(lh.value, rhtype.min())
1405+
== cls.eval_const(lh.value, rhtype.max())):
1406+
report(WTYPELIMITS(site, lh, rhtype))
13991407
rh_maybe_negative = rhtype.signed
14001408
rh = as_int(rh)
14011409
rhtype = realtype(rh.ctype())
@@ -1404,9 +1412,7 @@ def make(cls, site, lh, rh):
14041412
and lh_maybe_negative != rh_maybe_negative):
14051413
(signed_expr, unsigned_expr) = ((lh, rh) if lh_maybe_negative
14061414
else (rh, lh))
1407-
if signed_expr.constant and signed_expr.value < 0:
1408-
report(WNEGCONSTCOMP(site, signed_expr,
1409-
unsigned_expr.ctype()))
1415+
14101416
# we must convert (uint64)x < (int64)y to DML_lt(x, y), because
14111417
# C:'s < would do an unsigned comparison. No need to do this if y
14121418
# is a small constant, though.
@@ -1602,10 +1608,18 @@ def make(cls, site, lh, rh):
16021608
AddressOfMethod))
16031609
return mkBoolConstant(site, False)
16041610
if lhtype.is_int:
1611+
if rh.constant and rhtype.is_arith and (
1612+
not (lhtype.min() <= rh.value <= lhtype.max())
1613+
or (rhtype.is_float and rh.value % 1)):
1614+
report(WTYPELIMITS(site, rh, lhtype))
16051615
lh_maybe_negative = lhtype.signed
16061616
lh = as_int(lh)
16071617
lhtype = realtype(lh.ctype())
16081618
if rhtype.is_int:
1619+
if lh.constant and lhtype.is_arith and (
1620+
not (rhtype.min() <= lh.value <= rhtype.max())
1621+
or (lhtype.is_float and lh.value % 1)):
1622+
report(WTYPELIMITS(site, lh, rhtype))
16091623
rh_maybe_negative = rhtype.signed
16101624
rh = as_int(rh)
16111625
rhtype = realtype(rh.ctype())
@@ -1618,8 +1632,6 @@ def make(cls, site, lh, rh):
16181632
# unsigned to a constant literal.
16191633
(signed_expr, unsigned_expr) = ((lh, rh) if lh_maybe_negative
16201634
else (rh, lh))
1621-
if signed_expr.constant and signed_expr.value < 0:
1622-
report(WNEGCONSTCOMP(site, signed_expr, unsigned_expr.ctype()))
16231635
if not (signed_expr.constant and 0 <= signed_expr.value < 1 << 63):
16241636
return mkApply(
16251637
site, mkLit(

py/dml/ctree_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,9 +1186,9 @@ def compare_numeric(self, lh, rh, op, result):
11861186
rh_var = variable('rh', rh.ctype())
11871187
var_cond = op(site, lh_var, rh_var)
11881188
# compare constant and variable
1189-
logging.ignore_warning('WNEGCONSTCOMP')
1189+
logging.ignore_warning('WTYPELIMITS')
11901190
mix_cond = op(site, lh, rh_var)
1191-
logging.enable_warning('WNEGCONSTCOMP')
1191+
logging.enable_warning('WTYPELIMITS')
11921192
self.assertIsInstance(var_cond.ctype(), types.TBool)
11931193
self.assertIsInstance(mix_cond.ctype(), types.TBool)
11941194
return ['%s = %s;' % (lh.ctype().declaration('lh'), lh.read()),

py/dml/messages.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2110,16 +2110,18 @@ def log(self):
21102110
self.other_site,
21112111
"original non-throwing declaration")
21122112

2113-
class WNEGCONSTCOMP(DMLWarning):
2114-
"""DML uses a special method when comparing an unsigned and signed integer,
2115-
meaning that comparing a negative constant to an unsigned integer always
2116-
has the same result, which is usually not the intended behaviour."""
2113+
class WTYPELIMITS(DMLWarning):
2114+
"""When comparing an integer with a constant outside the range of the
2115+
integer's type, the comparison always has the same result. One
2116+
common example is that a value of type `uint64` always is
2117+
considered to be different from -1; in this case, the constant
2118+
can be rewritten as `cast(-1, uint64)`.
2119+
"""
21172120
def __init__(self, site, expr, ty):
2118-
DMLWarning.__init__(self, site)
2121+
super().__init__(site)
21192122
self.expr = expr
21202123
self.ty = ty
2121-
fmt = ("Comparing negative constant to unsigned integer has a constant "
2122-
+ "result")
2124+
fmt = 'Comparison with constant outside the range of data type'
21232125
def log(self):
21242126
DMLError.log(self)
21252127
self.print_site_message(

py/dml/types.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,17 @@ def __init__(self, bits, signed, members=None, const=False):
511511
is_arith = True
512512
is_endian = False
513513

514+
def min(self):
515+
if self.signed:
516+
return -(1 << (self.bits - 1))
517+
else:
518+
return 0
519+
def max(self):
520+
if self.signed:
521+
return (1 << (self.bits - 1)) - 1
522+
else:
523+
return (1 << self.bits) - 1
524+
514525
@property
515526
def is_bitfields(self):
516527
return self.members is not None

test/1.4/errors/T_WNEGCONSTCOMP.dml

Lines changed: 0 additions & 36 deletions
This file was deleted.

test/1.4/errors/T_WTYPELIMITS.dml

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
© 2021 Intel Corporation
3+
SPDX-License-Identifier: MPL-2.0
4+
*/
5+
dml 1.4;
6+
7+
device test;
8+
9+
method init() {
10+
local uint64 a = -1;
11+
// Test all operands
12+
/// WARNING WTYPELIMITS
13+
assert a != -1;
14+
/// WARNING WTYPELIMITS
15+
assert -1 != a;
16+
/// WARNING WTYPELIMITS
17+
assert !(-1 == a);
18+
/// WARNING WTYPELIMITS
19+
assert a > -1;
20+
/// WARNING WTYPELIMITS
21+
assert !(a < -1);
22+
/// WARNING WTYPELIMITS
23+
assert a >= -1;
24+
/// WARNING WTYPELIMITS
25+
assert !(a <= -1);
26+
27+
// Upper and lower bounds are tight, regardless if the constant is on RH or
28+
// LH side
29+
local uint8 a8 = -1;
30+
/// WARNING WTYPELIMITS
31+
assert a8 != -1;
32+
/// WARNING WTYPELIMITS
33+
assert -1 != a8;
34+
// no warning
35+
assert a8 != 0;
36+
assert 0 != a8;
37+
/// WARNING WTYPELIMITS
38+
assert a8 != 256;
39+
/// WARNING WTYPELIMITS
40+
assert 256 != a8;
41+
// no warning
42+
assert a8 == 255;
43+
assert 255 == a8;
44+
/// WARNING WTYPELIMITS
45+
assert a8 >= 0;
46+
/// WARNING WTYPELIMITS
47+
assert 0 <= a8;
48+
/// no warning
49+
assert a8 > 0;
50+
assert 0 < a8;
51+
/// WARNING WTYPELIMITS
52+
assert !(a8 > 255);
53+
/// WARNING WTYPELIMITS
54+
assert !(255 < a8);
55+
/// no warning
56+
assert a8 >= 255;
57+
assert 255 <= a8;
58+
59+
// Limits for signed integers are tight
60+
local int8 i8 = 128;
61+
/// WARNING WTYPELIMITS
62+
assert i8 != 128;
63+
// no warning
64+
assert i8 != 127;
65+
/// WARNING WTYPELIMITS
66+
assert i8 != -129;
67+
// no warning
68+
assert i8 == -128;
69+
70+
// Non-integer float constants also give warnings
71+
/// WARNING WTYPELIMITS
72+
assert i8 != 0.1;
73+
/// WARNING WTYPELIMITS
74+
assert 0.1 != i8;
75+
// no warning
76+
assert i8 != 0.0;
77+
assert 0.0 != i8;
78+
79+
// Sanity
80+
local int64 b = -1;
81+
// No warning
82+
assert b == -1;
83+
// No warning
84+
assert !(b < -1);
85+
86+
// Test workaround
87+
assert a == cast(-1, uint64);
88+
}

0 commit comments

Comments
 (0)