Skip to content

Commit 078151d

Browse files
committed
Implement stage B0 of PEP 237: add warnings for operations that
currently return inconsistent results for ints and longs; in particular: hex/oct/%u/%o/%x/%X of negative short ints, and x<<n that either loses bits or changes sign. (No warnings for repr() of a long, though that will also change to lose the trailing 'L' eventually.) This introduces some warnings in the test suite; I'll take care of those later.
1 parent d92ae84 commit 078151d

4 files changed

Lines changed: 50 additions & 4 deletions

File tree

Objects/intobject.c

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ int_invert(PyIntObject *v)
659659
static PyObject *
660660
int_lshift(PyIntObject *v, PyIntObject *w)
661661
{
662-
register long a, b;
662+
long a, b, c;
663663
CONVERT_TO_LONG(v, a);
664664
CONVERT_TO_LONG(w, b);
665665
if (b < 0) {
@@ -669,10 +669,20 @@ int_lshift(PyIntObject *v, PyIntObject *w)
669669
if (a == 0 || b == 0)
670670
return int_pos(v);
671671
if (b >= LONG_BIT) {
672+
if (PyErr_Warn(PyExc_DeprecationWarning,
673+
"x<<y losing bits or changing sign "
674+
"will return a long in Python 2.4 and up") < 0)
675+
return NULL;
672676
return PyInt_FromLong(0L);
673677
}
674-
a = (long)((unsigned long)a << b);
675-
return PyInt_FromLong(a);
678+
c = (long)((unsigned long)a << b);
679+
if ((c >> b) != a || (c < 0 && a > 0)) {
680+
if (PyErr_Warn(PyExc_DeprecationWarning,
681+
"x<<y losing bits or changing sign "
682+
"will return a long in Python 2.4 and up") < 0)
683+
return NULL;
684+
}
685+
return PyInt_FromLong(c);
676686
}
677687

678688
static PyObject *
@@ -761,6 +771,12 @@ int_oct(PyIntObject *v)
761771
{
762772
char buf[100];
763773
long x = v -> ob_ival;
774+
if (x < 0) {
775+
if (PyErr_Warn(PyExc_DeprecationWarning,
776+
"hex()/oct() of negative int will return "
777+
"a signed string in Python 2.4 and up") < 0)
778+
return NULL;
779+
}
764780
if (x == 0)
765781
strcpy(buf, "0");
766782
else
@@ -773,6 +789,12 @@ int_hex(PyIntObject *v)
773789
{
774790
char buf[100];
775791
long x = v -> ob_ival;
792+
if (x < 0) {
793+
if (PyErr_Warn(PyExc_DeprecationWarning,
794+
"hex()/oct() of negative int will return "
795+
"a signed string in Python 2.4 and up") < 0)
796+
return NULL;
797+
}
776798
PyOS_snprintf(buf, sizeof(buf), "0x%lx", x);
777799
return PyString_FromString(buf);
778800
}

Objects/stringobject.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3311,6 +3311,12 @@ formatint(char *buf, size_t buflen, int flags,
33113311
PyErr_SetString(PyExc_TypeError, "int argument required");
33123312
return -1;
33133313
}
3314+
if (x < 0 && type != 'd' && type != 'i') {
3315+
if (PyErr_Warn(PyExc_DeprecationWarning,
3316+
"%u/%o/%x/%X of negative int will return "
3317+
"a signed string in Python 2.4 and up") < 0)
3318+
return -1;
3319+
}
33143320
if (prec < 0)
33153321
prec = 1;
33163322

Objects/unicodeobject.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5219,6 +5219,10 @@ int usprintf(register Py_UNICODE *buffer, char *format, ...)
52195219
return len;
52205220
}
52215221

5222+
/* XXX To save some code duplication, formatfloat/long/int could have been
5223+
shared with stringobject.c, converting from 8-bit to Unicode after the
5224+
formatting is done. */
5225+
52225226
static int
52235227
formatfloat(Py_UNICODE *buf,
52245228
size_t buflen,
@@ -5294,6 +5298,12 @@ formatint(Py_UNICODE *buf,
52945298
x = PyInt_AsLong(v);
52955299
if (x == -1 && PyErr_Occurred())
52965300
return -1;
5301+
if (x < 0 && type != 'd' && type != 'i') {
5302+
if (PyErr_Warn(PyExc_DeprecationWarning,
5303+
"%u/%o/%x/%X of negative int will return "
5304+
"a signed string in Python 2.4 and up") < 0)
5305+
return -1;
5306+
}
52975307
if (prec < 0)
52985308
prec = 1;
52995309

Python/compile.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1154,8 +1154,16 @@ parsenumber(struct compiling *co, char *s)
11541154
#endif
11551155
if (*end == 'l' || *end == 'L')
11561156
return PyLong_FromString(s, (char **)0, 0);
1157-
if (s[0] == '0')
1157+
if (s[0] == '0') {
11581158
x = (long) PyOS_strtoul(s, &end, 0);
1159+
if (x < 0 && errno == 0) {
1160+
if (PyErr_Warn(PyExc_DeprecationWarning,
1161+
"hex/oct constants > sys.maxint "
1162+
"will return positive values "
1163+
"in Python 2.4 and up") < 0)
1164+
return NULL;
1165+
}
1166+
}
11591167
else
11601168
x = PyOS_strtol(s, &end, 0);
11611169
if (*end == '\0') {

0 commit comments

Comments
 (0)