Commit e6342238 authored by Robert Bradshaw's avatar Robert Bradshaw

Use warnings framework for c division.

parent 43ba295b
...@@ -4236,28 +4236,36 @@ class DivNode(NumBinopNode): ...@@ -4236,28 +4236,36 @@ class DivNode(NumBinopNode):
cdivision = None cdivision = None
cdivision_warnings = False cdivision_warnings = False
def analyse_types(self, env):
NumBinopNode.analyse_types(self, env)
if not self.type.is_pyobject and env.directives['cdivision_warnings']:
self.operand1 = self.operand1.coerce_to_simple(env)
self.operand2 = self.operand2.coerce_to_simple(env)
def generate_evaluation_code(self, code): def generate_evaluation_code(self, code):
if not self.type.is_pyobject: if not self.type.is_pyobject:
if self.cdivision is None: if self.cdivision is None:
self.cdivision = (code.globalstate.directives['cdivision'] self.cdivision = (code.globalstate.directives['cdivision']
or not self.type.signed or not self.type.signed
or self.type.is_float) or self.type.is_float)
if code.globalstate.directives['cdivision_warnings']: if not self.cdivision:
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)) code.globalstate.use_utility_code(div_utility_code.specialize(self.type))
NumBinopNode.generate_evaluation_code(self, code) NumBinopNode.generate_evaluation_code(self, code)
if not self.type.is_pyobject and code.globalstate.directives['cdivision_warnings']:
self.generate_div_warning_code(code)
def calculate_result_code(self): def generate_div_warning_code(self, code):
if self.cdivision_warnings: code.globalstate.use_utility_code(cdivision_warning_utility_code)
return "__Pyx_div_warn_%s(%s, %s, %s)" % ( code.putln("if ((%s < 0) ^ (%s < 0)) {" % (
self.type.specalization_name(),
self.operand1.result(), self.operand1.result(),
self.operand2.result(), self.operand2.result()))
int(self.cdivision)) code.putln(code.set_error_info(self.pos));
elif self.cdivision: code.put("if (__Pyx_cdivision_warning()) ")
code.put_goto(code.error_label)
code.putln("}")
def calculate_result_code(self):
if self.cdivision:
return "(%s / %s)" % ( return "(%s / %s)" % (
self.operand1.result(), self.operand1.result(),
self.operand2.result()) self.operand2.result())
...@@ -4280,27 +4288,19 @@ class ModNode(DivNode): ...@@ -4280,27 +4288,19 @@ class ModNode(DivNode):
if not self.type.is_pyobject: if not self.type.is_pyobject:
if self.cdivision is None: if self.cdivision is None:
self.cdivision = code.globalstate.directives['cdivision'] or not self.type.signed self.cdivision = code.globalstate.directives['cdivision'] or not self.type.signed
math_h_modifier = getattr(self.type, 'math_h_modifier', '__Pyx_INT') if not self.cdivision:
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: if self.type.is_int:
code.globalstate.use_utility_code(mod_int_helper_macro) code.globalstate.use_utility_code(mod_int_helper_macro)
math_h_modifier = '__Pyx_INT'
else:
math_h_modifier = self.type.math_h_modifier
code.globalstate.use_utility_code(mod_utility_code.specialize(self.type, math_h_modifier=math_h_modifier)) code.globalstate.use_utility_code(mod_utility_code.specialize(self.type, math_h_modifier=math_h_modifier))
NumBinopNode.generate_evaluation_code(self, code) NumBinopNode.generate_evaluation_code(self, code)
if not self.type.is_pyobject and code.globalstate.directives['cdivision_warnings']:
self.generate_div_warning_code(code)
def calculate_result_code(self): def calculate_result_code(self):
if self.cdivision_warnings: if self.cdivision:
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: if self.type.is_float:
return "fmod%s(%s, %s)" % ( return "fmod%s(%s, %s)" % (
self.type.math_h_modifier, self.type.math_h_modifier,
...@@ -5713,7 +5713,7 @@ static INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s, %(type)s); /* proto */ ...@@ -5713,7 +5713,7 @@ static INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s, %(type)s); /* proto */
impl=""" impl="""
static INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s a, %(type)s b) { static INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s a, %(type)s b) {
%(type)s res = fmod%(math_h_modifier)s(a, b); %(type)s res = fmod%(math_h_modifier)s(a, b);
res += (res * b < 0) * b; res += ((res < 0) ^ (b < 0)) * b;
return res; return res;
} }
""") """)
...@@ -5730,56 +5730,21 @@ static INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s a, %(type)s b) { ...@@ -5730,56 +5730,21 @@ static INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s a, %(type)s b) {
} }
""") """)
mod_warn_utility_code = UtilityCode( cdivision_warning_utility_code = UtilityCode(
proto=""" proto="""
static INLINE %(type)s __Pyx_mod_warn_%(type_name)s(%(type)s, %(type)s, int cdivision); /* proto */ static int __Pyx_cdivision_warning(void); /* proto */
""", """,
impl=""" impl="""
static INLINE %(type)s __Pyx_mod_warn_%(type_name)s(%(type)s a, %(type)s b, int cdivision) { static int __Pyx_cdivision_warning(void) {
%(type)s res = fmod%(math_h_modifier)s(a, b); return PyErr_WarnExplicit(PyExc_RuntimeWarning,
if (res * b < 0) { "division with oppositely signed operands, C and Python semantics differ",
__Pyx_div_mod_warning(); %(FILENAME)s,
if (!cdivision) res += b; %(LINENO)s,
} %(MODULENAME)s,
return res; NULL);
} }
""") """ % {
'FILENAME': Naming.filename_cname,
div_warn_utility_code = UtilityCode( 'MODULENAME': Naming.modulename_cname,
proto=""" 'LINENO': Naming.lineno_cname,
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])
...@@ -253,6 +253,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -253,6 +253,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.globalstate.use_utility_code(refcount_utility_code) code.globalstate.use_utility_code(refcount_utility_code)
code.putln('const char *%s = "%s";' % (Naming.modulename_cname, self.full_module_name))
code.putln("") code.putln("")
code.putln("/* Implementation of %s */" % env.qualified_name) code.putln("/* Implementation of %s */" % env.qualified_name)
self.generate_const_definitions(env, code) self.generate_const_definitions(env, code)
......
...@@ -52,6 +52,7 @@ preimport_cname = pyrex_prefix + "i" ...@@ -52,6 +52,7 @@ preimport_cname = pyrex_prefix + "i"
moddict_cname = pyrex_prefix + "d" moddict_cname = pyrex_prefix + "d"
dummy_cname = pyrex_prefix + "dummy" dummy_cname = pyrex_prefix + "dummy"
filename_cname = pyrex_prefix + "filename" filename_cname = pyrex_prefix + "filename"
modulename_cname = pyrex_prefix + "modulename"
filetable_cname = pyrex_prefix + "f" filetable_cname = pyrex_prefix + "f"
filenames_cname = pyrex_prefix + "filenames" filenames_cname = pyrex_prefix + "filenames"
fileinit_cname = pyrex_prefix + "init_filenames" fileinit_cname = pyrex_prefix + "init_filenames"
......
...@@ -5342,32 +5342,6 @@ bad: ...@@ -5342,32 +5342,6 @@ bad:
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
unraisable_exception_utility_code = UtilityCode(
proto = """
static void __Pyx_WriteUnraisable(const char *name); /*proto*/
""",
impl = """
static void __Pyx_WriteUnraisable(const char *name) {
PyObject *old_exc, *old_val, *old_tb;
PyObject *ctx;
__Pyx_ErrFetch(&old_exc, &old_val, &old_tb);
#if PY_MAJOR_VERSION < 3
ctx = PyString_FromString(name);
#else
ctx = PyUnicode_FromString(name);
#endif
__Pyx_ErrRestore(old_exc, old_val, old_tb);
if (!ctx) {
PyErr_WriteUnraisable(Py_None);
} else {
PyErr_WriteUnraisable(ctx);
Py_DECREF(ctx);
}
}
""")
#------------------------------------------------------------------------------------
traceback_utility_code = UtilityCode( traceback_utility_code = UtilityCode(
proto = """ proto = """
static void __Pyx_AddTraceback(const char *funcname); /*proto*/ static void __Pyx_AddTraceback(const char *funcname); /*proto*/
...@@ -5512,6 +5486,33 @@ static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject ** ...@@ -5512,6 +5486,33 @@ static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
unraisable_exception_utility_code = UtilityCode(
proto = """
static void __Pyx_WriteUnraisable(const char *name); /*proto*/
""",
impl = """
static void __Pyx_WriteUnraisable(const char *name) {
PyObject *old_exc, *old_val, *old_tb;
PyObject *ctx;
__Pyx_ErrFetch(&old_exc, &old_val, &old_tb);
#if PY_MAJOR_VERSION < 3
ctx = PyString_FromString(name);
#else
ctx = PyUnicode_FromString(name);
#endif
__Pyx_ErrRestore(old_exc, old_val, old_tb);
if (!ctx) {
PyErr_WriteUnraisable(Py_None);
} else {
PyErr_WriteUnraisable(ctx);
Py_DECREF(ctx);
}
}
""",
requires=[restore_exception_utility_code])
#------------------------------------------------------------------------------------
set_vtable_utility_code = UtilityCode( set_vtable_utility_code = UtilityCode(
proto = """ proto = """
static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/ static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/
......
...@@ -27,12 +27,23 @@ True ...@@ -27,12 +27,23 @@ True
>>> [test_cdiv_cmod(a, b) for a, b in v] >>> [test_cdiv_cmod(a, b) for a, b in v]
[(1, 7), (-1, -7), (1, -7), (-1, 7)] [(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 >>> def simple_warn(msg, *args): print msg
>>> import warnings
>>> warnings.showwarning = simple_warn
>>> mod_int_c_warn(-17, 10)
division with oppositely signed operands, C and Python semantics differ
-7 -7
>>> div_int_py_warn(-17, 10) >>> div_int_c_warn(-17, 10)
Warning: division with oppositely signed operands, C and Python semantics differ division with oppositely signed operands, C and Python semantics differ
-1 -1
>>> complex_expression(-150, 20, 20, -7)
verbose_call(-150)
division with oppositely signed operands, C and Python semantics differ
verbose_call(20)
division with oppositely signed operands, C and Python semantics differ
-2
""" """
cimport cython cimport cython
...@@ -83,10 +94,19 @@ def test_cdiv_cmod(short a, short b): ...@@ -83,10 +94,19 @@ def test_cdiv_cmod(short a, short b):
@cython.cdivision(True) @cython.cdivision(True)
@cython.cdivision_warnings(True) @cython.cdivision_warnings(True)
def mod_int_py_warn(int a, int b): def mod_int_c_warn(int a, int b):
return a % b return a % b
@cython.cdivision(True) @cython.cdivision(True)
@cython.cdivision_warnings(True) @cython.cdivision_warnings(True)
def div_int_py_warn(int a, int b): def div_int_c_warn(int a, int b):
return a // b return a // b
@cython.cdivision(False)
@cython.cdivision_warnings(True)
def complex_expression(int a, int b, int c, int d):
return (verbose_call(a) // b) % (verbose_call(c) // d)
cdef int verbose_call(int x):
print "verbose_call(%s)" % x
return x
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment