CDP 516 warnings
authorRobert Bradshaw <robertwb@math.washington.edu>
Sat, 28 Mar 2009 06:26:39 +0000 (23:26 -0700)
committerRobert Bradshaw <robertwb@math.washington.edu>
Sat, 28 Mar 2009 06:26:39 +0000 (23:26 -0700)
Cython/Compiler/ExprNodes.py
Cython/Compiler/Nodes.py
Cython/Compiler/Options.py
tests/run/cdivision_CEP_516.pyx

index beb6236140dc590e2466669885afab6968b6a9fb..f9a825d20600b466e7720cb8a342691ab3710260 100644 (file)
@@ -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])
index 51601ca09f9fa08826bfeae7bf7d78683578c64a..71638ffcdd0b23a7d735c61f944fcc1761294652 100644 (file)
@@ -4976,7 +4976,8 @@ static int __Pyx_PrintOne(PyObject *o) {
 }
 
 #endif
-""")
+""",
+requires=[printing_utility_code])
 
 
 
index de14a810fa590f5399a83e26240ae3626803431b..c397aeaf6078d896573cd86450429f6c3932544b 100644 (file)
@@ -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
index b0b05c441bc9437e5366e997ce8b4842d643643f..ca857cc80579c8d8ac6406a3431c30bfa1131c10 100644 (file)
@@ -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