From e634223846689605cffd7c58cb138eda28722388 Mon Sep 17 00:00:00 2001 From: Robert Bradshaw Date: Sat, 28 Mar 2009 02:22:07 -0700 Subject: [PATCH] Use warnings framework for c division. --- Cython/Compiler/ExprNodes.py | 119 +++++++++++--------------------- Cython/Compiler/ModuleNode.py | 1 + Cython/Compiler/Naming.py | 1 + Cython/Compiler/Nodes.py | 53 +++++++------- tests/run/cdivision_CEP_516.pyx | 32 +++++++-- 5 files changed, 97 insertions(+), 109 deletions(-) diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index f9a825d2..282ecb3c 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -4235,6 +4235,12 @@ class DivNode(NumBinopNode): cdivision = None 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): if not self.type.is_pyobject: @@ -4242,22 +4248,24 @@ class DivNode(NumBinopNode): self.cdivision = (code.globalstate.directives['cdivision'] or not self.type.signed or self.type.is_float) - 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: + if not self.cdivision: code.globalstate.use_utility_code(div_utility_code.specialize(self.type)) 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 generate_div_warning_code(self, code): + code.globalstate.use_utility_code(cdivision_warning_utility_code) + code.putln("if ((%s < 0) ^ (%s < 0)) {" % ( + self.operand1.result(), + self.operand2.result())) + code.putln(code.set_error_info(self.pos)); + code.put("if (__Pyx_cdivision_warning()) ") + code.put_goto(code.error_label) + code.putln("}") def calculate_result_code(self): - 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: + if self.cdivision: return "(%s / %s)" % ( self.operand1.result(), self.operand2.result()) @@ -4280,27 +4288,19 @@ class ModNode(DivNode): if not self.type.is_pyobject: if self.cdivision is None: self.cdivision = code.globalstate.directives['cdivision'] or not self.type.signed - 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 not self.cdivision: if self.type.is_int: 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)) 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): - 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.cdivision: if self.type.is_float: return "fmod%s(%s, %s)" % ( self.type.math_h_modifier, @@ -5713,7 +5713,7 @@ static INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s, %(type)s); /* proto */ impl=""" 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); - res += (res * b < 0) * b; + res += ((res < 0) ^ (b < 0)) * b; return res; } """) @@ -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=""" -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=""" -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; +static int __Pyx_cdivision_warning(void) { + return PyErr_WarnExplicit(PyExc_RuntimeWarning, + "division with oppositely signed operands, C and Python semantics differ", + %(FILENAME)s, + %(LINENO)s, + %(MODULENAME)s, + NULL); } -""") - -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]) +""" % { + 'FILENAME': Naming.filename_cname, + 'MODULENAME': Naming.modulename_cname, + 'LINENO': Naming.lineno_cname, +}) diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index e3cb4b6f..21c62a8e 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -253,6 +253,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): 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("/* Implementation of %s */" % env.qualified_name) self.generate_const_definitions(env, code) diff --git a/Cython/Compiler/Naming.py b/Cython/Compiler/Naming.py index bfed035e..7864efdb 100644 --- a/Cython/Compiler/Naming.py +++ b/Cython/Compiler/Naming.py @@ -52,6 +52,7 @@ preimport_cname = pyrex_prefix + "i" moddict_cname = pyrex_prefix + "d" dummy_cname = pyrex_prefix + "dummy" filename_cname = pyrex_prefix + "filename" +modulename_cname = pyrex_prefix + "modulename" filetable_cname = pyrex_prefix + "f" filenames_cname = pyrex_prefix + "filenames" fileinit_cname = pyrex_prefix + "init_filenames" diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 71638ffc..a5154ead 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -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( proto = """ static void __Pyx_AddTraceback(const char *funcname); /*proto*/ @@ -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( proto = """ static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/ diff --git a/tests/run/cdivision_CEP_516.pyx b/tests/run/cdivision_CEP_516.pyx index ca857cc8..29269001 100644 --- a/tests/run/cdivision_CEP_516.pyx +++ b/tests/run/cdivision_CEP_516.pyx @@ -27,12 +27,23 @@ 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 + +>>> 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 ->>> div_int_py_warn(-17, 10) -Warning: division with oppositely signed operands, C and Python semantics differ +>>> div_int_c_warn(-17, 10) +division with oppositely signed operands, C and Python semantics differ -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 @@ -83,10 +94,19 @@ def test_cdiv_cmod(short a, short b): @cython.cdivision(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 @cython.cdivision(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 + +@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 -- 2.26.2