From: Robert Bradshaw Date: Sat, 28 Mar 2009 06:26:39 +0000 (-0700) Subject: CDP 516 warnings X-Git-Tag: 0.12.alpha0~334^2~8 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=43ba295b703a31c51f6c2446847ed9527325cba7;p=cython.git CDP 516 warnings --- diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index beb62361..f9a825d2 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -9,6 +9,7 @@ from Errors import hold_errors, release_errors, held_errors, report_error from Cython.Utils import UtilityCode import StringEncoding import Naming +import Nodes from Nodes import Node import PyrexTypes from PyrexTypes import py_object_type, c_long_type, typecast, error_type @@ -4233,19 +4234,30 @@ class DivNode(NumBinopNode): # '/' or '//' operator. cdivision = None - + cdivision_warnings = False + def generate_evaluation_code(self, code): if not self.type.is_pyobject: if self.cdivision is None: self.cdivision = (code.globalstate.directives['cdivision'] or not self.type.signed or self.type.is_float) - if not self.cdivision: + if code.globalstate.directives['cdivision_warnings']: + self.cdivision_warnings = True + code.globalstate.use_utility_code(div_mod_print_warning_utility_code) + code.globalstate.use_utility_code(div_warn_utility_code.specialize(self.type)) + elif not self.cdivision: code.globalstate.use_utility_code(div_utility_code.specialize(self.type)) NumBinopNode.generate_evaluation_code(self, code) def calculate_result_code(self): - if self.cdivision: + if self.cdivision_warnings: + return "__Pyx_div_warn_%s(%s, %s, %s)" % ( + self.type.specalization_name(), + self.operand1.result(), + self.operand2.result(), + int(self.cdivision)) + elif self.cdivision: return "(%s / %s)" % ( self.operand1.result(), self.operand2.result()) @@ -4256,11 +4268,9 @@ class DivNode(NumBinopNode): self.operand2.result()) -class ModNode(NumBinopNode): +class ModNode(DivNode): # '%' operator. - cdivision = None - def is_py_operation(self): return (self.operand1.type.is_string or self.operand2.type.is_string @@ -4270,15 +4280,27 @@ class ModNode(NumBinopNode): if not self.type.is_pyobject: if self.cdivision is None: self.cdivision = code.globalstate.directives['cdivision'] or not self.type.signed - if not self.cdivision: - math_h_modifier = getattr(self.type, 'math_h_modifier', '__Pyx_INT') + math_h_modifier = getattr(self.type, 'math_h_modifier', '__Pyx_INT') + if code.globalstate.directives['cdivision_warnings']: + self.cdivision_warnings = True + if self.type.is_int: + code.globalstate.use_utility_code(mod_int_helper_macro) + code.globalstate.use_utility_code(div_mod_print_warning_utility_code) + code.globalstate.use_utility_code(mod_warn_utility_code.specialize(self.type, math_h_modifier=math_h_modifier)) + elif not self.cdivision: if self.type.is_int: code.globalstate.use_utility_code(mod_int_helper_macro) code.globalstate.use_utility_code(mod_utility_code.specialize(self.type, math_h_modifier=math_h_modifier)) NumBinopNode.generate_evaluation_code(self, code) def calculate_result_code(self): - if self.cdivision: + if self.cdivision_warnings: + return "__Pyx_mod_warn_%s(%s, %s, %s)" % ( + self.type.specalization_name(), + self.operand1.result(), + self.operand2.result(), + int(self.cdivision)) + elif self.cdivision: if self.type.is_float: return "fmod%s(%s, %s)" % ( self.type.math_h_modifier, @@ -5707,3 +5729,57 @@ static INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s a, %(type)s b) { return res; } """) + +mod_warn_utility_code = UtilityCode( +proto=""" +static INLINE %(type)s __Pyx_mod_warn_%(type_name)s(%(type)s, %(type)s, int cdivision); /* proto */ +""", +impl=""" +static INLINE %(type)s __Pyx_mod_warn_%(type_name)s(%(type)s a, %(type)s b, int cdivision) { + %(type)s res = fmod%(math_h_modifier)s(a, b); + if (res * b < 0) { + __Pyx_div_mod_warning(); + if (!cdivision) res += b; + } + return res; +} +""") + +div_warn_utility_code = UtilityCode( +proto=""" +static INLINE %(type)s __Pyx_div_warn_%(type_name)s(%(type)s, %(type)s, int cdivision); /* proto */ +""", +impl=""" +static INLINE %(type)s __Pyx_div_warn_%(type_name)s(%(type)s a, %(type)s b, int cdivision) { + %(type)s res = a / b; + if (res < 0) { + if (__Pyx_div_mod_warning()) ; + if (!cdivision) res -= 1; + } + return res; +} +""") + + +div_mod_print_warning_utility_code = UtilityCode( +proto=""" +static int __Pyx_div_mod_warning(void); /* proto */ +""", +impl=""" +static int __Pyx_div_mod_warning(void) { + int r; + PyObject* s; + #if PY_MAJOR_VERSION < 3 + s = PyString_FromString("Warning: division with oppositely signed operands, C and Python semantics differ"); + #else + s = PyUnicode_FromString("Warning: division with oppositely signed operands, C and Python semantics differ"); + #endif + if (s) { + r = __Pyx_PrintOne(s); + Py_DECREF(s); + } + else r = -1; + return r; +} +""", +requires=[Nodes.printing_one_utility_code]) diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 51601ca0..71638ffc 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -4976,7 +4976,8 @@ static int __Pyx_PrintOne(PyObject *o) { } #endif -""") +""", +requires=[printing_utility_code]) diff --git a/Cython/Compiler/Options.py b/Cython/Compiler/Options.py index de14a810..c397aeaf 100644 --- a/Cython/Compiler/Options.py +++ b/Cython/Compiler/Options.py @@ -62,6 +62,7 @@ option_defaults = { 'locals' : {}, 'auto_cpdef': False, 'cdivision': True, # Will be False in 0.12 + 'cdivision_warnings': False, } # Override types possibilities above, if needed diff --git a/tests/run/cdivision_CEP_516.pyx b/tests/run/cdivision_CEP_516.pyx index b0b05c44..ca857cc8 100644 --- a/tests/run/cdivision_CEP_516.pyx +++ b/tests/run/cdivision_CEP_516.pyx @@ -26,6 +26,13 @@ True >>> [test_cdiv_cmod(a, b) for a, b in v] [(1, 7), (-1, -7), (1, -7), (-1, 7)] + +>>> mod_int_py_warn(-17, 10) +Warning: division with oppositely signed operands, C and Python semantics differ +-7 +>>> div_int_py_warn(-17, 10) +Warning: division with oppositely signed operands, C and Python semantics differ +-1 """ cimport cython @@ -73,3 +80,13 @@ def test_cdiv_cmod(short a, short b): cdef short q = cython.cdiv(a, b) cdef short r = cython.cmod(a, b) return q, r + +@cython.cdivision(True) +@cython.cdivision_warnings(True) +def mod_int_py_warn(int a, int b): + return a % b + +@cython.cdivision(True) +@cython.cdivision_warnings(True) +def div_int_py_warn(int a, int b): + return a // b