Commit 7676b4a9 authored by Robert Bradshaw's avatar Robert Bradshaw

cdivision - raise zero division errors

parent 341dcb8a
...@@ -4237,12 +4237,22 @@ class DivNode(NumBinopNode): ...@@ -4237,12 +4237,22 @@ class DivNode(NumBinopNode):
cdivision = None cdivision = None
cdivision_warnings = False cdivision_warnings = False
zerodivision_check = None
def analyse_types(self, env): def analyse_types(self, env):
NumBinopNode.analyse_types(self, env) NumBinopNode.analyse_types(self, env)
if not self.type.is_pyobject and env.directives['cdivision_warnings']: if not self.type.is_pyobject:
self.operand1 = self.operand1.coerce_to_simple(env) self.zerodivision_check = self.cdivision is None and not env.directives['cdivision']
self.operand2 = self.operand2.coerce_to_simple(env) if self.zerodivision_check or env.directives['cdivision_warnings']:
# Need to check ahead of time to warn or raise zero division error
self.operand1 = self.operand1.coerce_to_simple(env)
self.operand2 = self.operand2.coerce_to_simple(env)
def zero_division_message(self):
if self.type.is_int:
return "integer division or modulo by zero"
else:
return "float division"
def generate_evaluation_code(self, code): def generate_evaluation_code(self, code):
if not self.type.is_pyobject: if not self.type.is_pyobject:
...@@ -4253,18 +4263,24 @@ class DivNode(NumBinopNode): ...@@ -4253,18 +4263,24 @@ class DivNode(NumBinopNode):
if not self.cdivision: if not self.cdivision:
code.globalstate.use_utility_code(div_int_utility_code.specialize(self.type)) code.globalstate.use_utility_code(div_int_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)
self.generate_div_warning_code(code)
def generate_div_warning_code(self, code): def generate_div_warning_code(self, code):
code.globalstate.use_utility_code(cdivision_warning_utility_code) if not self.type.is_pyobject:
code.putln("if ((%s < 0) ^ (%s < 0)) {" % ( if self.zerodivision_check:
self.operand1.result(), code.putln("if (unlikely(%s == 0)) {" % self.operand2.result())
self.operand2.result())) code.putln('PyErr_Format(PyExc_ZeroDivisionError, "%s");' % self.zero_division_message())
code.putln(code.set_error_info(self.pos)); code.putln(code.error_goto(self.pos))
code.put("if (__Pyx_cdivision_warning()) ") code.putln("}")
code.put_goto(code.error_label) if code.globalstate.directives['cdivision_warnings']:
code.putln("}") 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): def calculate_result_code(self):
if self.type.is_float and self.operator == '//': if self.type.is_float and self.operator == '//':
...@@ -4290,6 +4306,12 @@ class ModNode(DivNode): ...@@ -4290,6 +4306,12 @@ class ModNode(DivNode):
or self.operand2.type.is_string or self.operand2.type.is_string
or NumBinopNode.is_py_operation(self)) or NumBinopNode.is_py_operation(self))
def zero_division_message(self):
if self.type.is_int:
return "integer division or modulo by zero"
else:
return "float divmod()"
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:
...@@ -4301,8 +4323,7 @@ class ModNode(DivNode): ...@@ -4301,8 +4323,7 @@ class ModNode(DivNode):
code.globalstate.use_utility_code( code.globalstate.use_utility_code(
mod_float_utility_code.specialize(self.type, math_h_modifier=self.type.math_h_modifier)) mod_float_utility_code.specialize(self.type, math_h_modifier=self.type.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)
self.generate_div_warning_code(code)
def calculate_result_code(self): def calculate_result_code(self):
if self.cdivision: if self.cdivision:
......
...@@ -42,12 +42,28 @@ division with oppositely signed operands, C and Python semantics differ ...@@ -42,12 +42,28 @@ division with oppositely signed operands, C and Python semantics differ
>>> div_int_c_warn(-17, 10) >>> div_int_c_warn(-17, 10)
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) >>> complex_expression(-150, 20, 19, -7)
verbose_call(-150)
division with oppositely signed operands, C and Python semantics differ
verbose_call(20) verbose_call(20)
division with oppositely signed operands, C and Python semantics differ division with oppositely signed operands, C and Python semantics differ
verbose_call(19)
division with oppositely signed operands, C and Python semantics differ
-2 -2
>>> mod_div_zero_int(25, 10, 2)
verbose_call(5)
2
>>> mod_div_zero_int(25, 10, 0)
verbose_call(5)
'integer division or modulo by zero'
>>> mod_div_zero_int(25, 0, 0)
'integer division or modulo by zero'
>>> mod_div_zero_float(25, 10, 2)
2.5
>>> mod_div_zero_float(25, 10, 0)
'float division'
>>> mod_div_zero_float(25, 0, 0)
'float divmod()'
""" """
cimport cython cimport cython
...@@ -109,8 +125,25 @@ def div_int_c_warn(int a, int b): ...@@ -109,8 +125,25 @@ def div_int_c_warn(int a, int b):
@cython.cdivision(False) @cython.cdivision(False)
@cython.cdivision_warnings(True) @cython.cdivision_warnings(True)
def complex_expression(int a, int b, int c, int d): def complex_expression(int a, int b, int c, int d):
return (verbose_call(a) // b) % (verbose_call(c) // d) return (a // verbose_call(b)) % (verbose_call(c) // d)
cdef int verbose_call(int x): cdef int verbose_call(int x):
print "verbose_call(%s)" % x print "verbose_call(%s)" % x
return x return x
# These may segfault with cdivision
@cython.cdivision(False)
def mod_div_zero_int(int a, int b, int c):
try:
return verbose_call(a % b) / c
except ZeroDivisionError, ex:
return ex.message
@cython.cdivision(False)
def mod_div_zero_float(float a, float b, float c):
try:
return (a % b) / c
except ZeroDivisionError, ex:
return ex.message
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