Commit 072b05eb authored by Robert Bradshaw's avatar Robert Bradshaw

C++ error handling

parent 14ec6047
...@@ -889,7 +889,7 @@ class NameNode(AtomicExprNode): ...@@ -889,7 +889,7 @@ class NameNode(AtomicExprNode):
def check_const(self): def check_const(self):
entry = self.entry entry = self.entry
if not (entry.is_const or entry.is_cfunction or entry.is_builtin): if entry is not None and not (entry.is_const or entry.is_cfunction or entry.is_builtin):
self.not_const() self.not_const()
def check_const_addr(self): def check_const_addr(self):
...@@ -1604,7 +1604,11 @@ class SimpleCallNode(ExprNode): ...@@ -1604,7 +1604,11 @@ class SimpleCallNode(ExprNode):
self.is_temp = 1 self.is_temp = 1
if self.type.is_pyobject: if self.type.is_pyobject:
self.result_ctype = py_object_type self.result_ctype = py_object_type
# C++ exception handler
if func_type.exception_check == '+':
if func_type.exception_value is None:
env.use_utility_code(cpp_exception_utility_code)
def calculate_result_code(self): def calculate_result_code(self):
return self.c_call_code() return self.c_call_code()
...@@ -1678,12 +1682,18 @@ class SimpleCallNode(ExprNode): ...@@ -1678,12 +1682,18 @@ class SimpleCallNode(ExprNode):
rhs = typecast(py_object_type, self.type, rhs) rhs = typecast(py_object_type, self.type, rhs)
else: else:
lhs = "" lhs = ""
# <fsw> added for generating C++ try/catch block
if func_type.exception_check == '+': if func_type.exception_check == '+':
if func_type.exception_value is None:
raise_py_exception = "__Pyx_CppExn2PyErr()"
elif func_type.exception_value.type.is_pyobject:
raise_py_exception = 'PyErr_SetString(%s, "")' % func_type.exception_value.entry.cname
else:
raise_py_exception = '%s(); if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError , "Error converting c++ exception.")' % func_type.exception_value.entry.cname
code.putln( code.putln(
"try {%s%s;} catch(...) {CppExn2PyErr(); %s}" % ( "try {%s%s;} catch(...) {%s; %s}" % (
lhs, lhs,
rhs, rhs,
raise_py_exception,
code.error_goto(self.pos))) code.error_goto(self.pos)))
return return
code.putln( code.putln(
...@@ -4036,3 +4046,28 @@ bad: ...@@ -4036,3 +4046,28 @@ bad:
"""] """]
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
cpp_exception_utility_code = [
"""
static int __Pyx_CppExn2PyErr(); /*proto*/
""","""
void __Pyx_CppExn2PyErr() {
try {
if (PyErr_Occurred())
; // let the latest Python exn pass through and ignore the current one
else
throw;
} catch (const std::out_of_range& exn) {
// catch out_of_range explicitly so the proper Python exn may be raised
PyErr_SetString(PyExc_IndexError, exn.what());
} catch (const std::exception& exn) {
PyErr_SetString(PyExc_RuntimeError, exn.what());
}
catch (...)
{
PyErr_SetString(PyExc_RuntimeError, "Unknown exception");
}
}
"""]
#------------------------------------------------------------------------------------
...@@ -483,10 +483,19 @@ class CFuncDeclaratorNode(CDeclaratorNode): ...@@ -483,10 +483,19 @@ class CFuncDeclaratorNode(CDeclaratorNode):
else: else:
if self.exception_value: if self.exception_value:
self.exception_value.analyse_const_expression(env) self.exception_value.analyse_const_expression(env)
exc_val = self.exception_value.result_code if self.exception_check == '+':
if not return_type.assignable_from(self.exception_value.type): exc_val_type = self.exception_value.type
error(self.exception_value.pos, if not exc_val_type.is_error and \
"Exception value incompatible with function return type") not exc_val_type.is_pyobject and \
not (exc_val_type.is_cfunction and not exc_val_type.return_type.is_pyobject and len(exc_val_type.args)==0):
error(self.exception_value.pos,
"Exception value must be a Python exception or cdef function with no arguments.")
exc_val = self.exception_value
else:
exc_val = self.exception_value.result_code
if not return_type.assignable_from(self.exception_value.type):
error(self.exception_value.pos,
"Exception value incompatible with function return type")
exc_check = self.exception_check exc_check = self.exception_check
if return_type.is_pyobject and self.nogil: if return_type.is_pyobject and self.nogil:
error(self.pos, error(self.pos,
......
...@@ -1648,6 +1648,10 @@ def p_exception_value_clause(s): ...@@ -1648,6 +1648,10 @@ def p_exception_value_clause(s):
elif s.sy == '+': elif s.sy == '+':
exc_check = '+' exc_check = '+'
s.next() s.next()
if s.sy == 'IDENT':
name = s.systring
s.next()
exc_val = p_name(s, name)
else: else:
if s.sy == '?': if s.sy == '?':
exc_check = 1 exc_check = 1
......
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