diff options
author | Tim Peters <tim.peters@gmail.com> | 2001-09-07 08:45:55 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2001-09-07 08:45:55 (GMT) |
commit | 51e2651b298cf59653133baf556f4cca3c569583 (patch) | |
tree | c2e498784340f340ce0809b2df18237955dca40a /Python | |
parent | 9652de9d825f2e377c4238145cc914bd28fa7111 (diff) | |
download | cpython-51e2651b298cf59653133baf556f4cca3c569583.zip cpython-51e2651b298cf59653133baf556f4cca3c569583.tar.gz cpython-51e2651b298cf59653133baf556f4cca3c569583.tar.bz2 |
SF bug [#458941] Looks like a unary minus bug.
com_factor(): when a unary minus is attached to a float or imaginary zero,
don't optimize the UNARY_MINUS opcode away: the const dict can't
distinguish between +0.0 and -0.0, so ended up treating both like the
first one added to it. Optimizing UNARY_PLUS away isn't a problem.
(BTW, I already uploaded the 2.2a3 Windows installer, and this isn't
important enough to delay the release.)
Diffstat (limited to 'Python')
-rw-r--r-- | Python/compile.c | 65 |
1 files changed, 49 insertions, 16 deletions
diff --git a/Python/compile.c b/Python/compile.c index 171fceb..ec7daaf 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1879,44 +1879,77 @@ com_invert_constant(struct compiling *c, node *n) com_addbyte(c, UNARY_INVERT); } +static int +is_float_zero(const char *p) +{ + int found_radix_point = 0; + int ch; + while ((ch = Py_CHARMASK(*p++)) != '\0') { + switch (ch) { + case '0': + /* no reason to believe it's not 0 -- continue */ + break; + + case 'e': case 'E': case 'j': case 'J': + /* If this was a hex constant, we already would have + returned 0 due to the 'x' or 'X', so 'e' or 'E' + must be an exponent marker, and we haven't yet + seen a non-zero digit, and it doesn't matter what + the exponent is then. For 'j' or 'J' similarly, + except that this is an imaginary 0 then. */ + return 1; + + case '.': + found_radix_point = 1; + break; + + default: + return 0; + } + } + return found_radix_point; +} + static void com_factor(struct compiling *c, node *n) { int childtype = TYPE(CHILD(n, 0)); + node *pfactor, *ppower, *patom, *pnum; REQ(n, factor); /* If the unary +, -, or ~ operator is applied to a constant, - don't generate a UNARY_xxx opcode. Just store the + don't generate a UNARY_xxx opcode. Just store the approriate value as a constant. If the value is negative, extend the string containing the constant and insert a - negative in the 0th position. + negative in the 0th position -- unless we're doing unary minus + of a floating zero! In that case the sign is significant, but + the const dict can't distinguish +0.0 from -0.0. */ if ((childtype == PLUS || childtype == MINUS || childtype == TILDE) && NCH(n) == 2 - && TYPE(CHILD(n, 1)) == factor - && NCH(CHILD(n, 1)) == 1 - && TYPE(CHILD(CHILD(n, 1), 0)) == power - && NCH(CHILD(CHILD(n, 1), 0)) == 1 - && TYPE(CHILD(CHILD(CHILD(n, 1), 0), 0)) == atom - && TYPE(CHILD(CHILD(CHILD(CHILD(n, 1), 0), 0), 0)) == NUMBER) { - node *constant = CHILD(CHILD(CHILD(n, 1), 0), 0); + && TYPE((pfactor = CHILD(n, 1))) == factor + && NCH(pfactor) == 1 + && TYPE((ppower = CHILD(pfactor, 0))) == power + && NCH(ppower) == 1 + && TYPE((patom = CHILD(ppower, 0))) == atom + && TYPE((pnum = CHILD(patom, 0))) == NUMBER + && !(childtype == MINUS && is_float_zero(STR(pnum)))) { if (childtype == TILDE) { - com_invert_constant(c, CHILD(constant, 0)); + com_invert_constant(c, pnum); return; } if (childtype == MINUS) { - node *numnode = CHILD(constant, 0); - char *s = malloc(strlen(STR(numnode)) + 2); + char *s = malloc(strlen(STR(pnum)) + 2); if (s == NULL) { com_error(c, PyExc_MemoryError, ""); com_addbyte(c, 255); return; } s[0] = '-'; - strcpy(s + 1, STR(numnode)); - free(STR(numnode)); - STR(numnode) = s; + strcpy(s + 1, STR(pnum)); + free(STR(pnum)); + STR(pnum) = s; } - com_atom(c, constant); + com_atom(c, patom); } else if (childtype == PLUS) { com_factor(c, CHILD(n, 1)); |