Commit fc2de434 authored by Stefan Behnel's avatar Stefan Behnel

back up and restore complete exception state around 'finally' clauses; move...

back up and restore complete exception state around 'finally' clauses; move current exception into sys.exc_info in Py3 to match Py3 semantics
parent 7be3a015
...@@ -6464,9 +6464,8 @@ class TryFinallyStatNode(StatNode): ...@@ -6464,9 +6464,8 @@ class TryFinallyStatNode(StatNode):
exc_lineno_cnames = exc_filename_cname = None exc_lineno_cnames = exc_filename_cname = None
exc_vars = tuple([ exc_vars = tuple([
code.funcstate.allocate_temp(py_object_type, manage_ref=False) code.funcstate.allocate_temp(py_object_type, manage_ref=False)
for _ in range(3)]) for _ in range(6)])
code.put_label(new_error_label) code.put_label(new_error_label)
code.putln("%s = 0; %s = 0; %s = 0;" % exc_vars)
self.put_error_catcher( self.put_error_catcher(
code, temps_to_clean_up, exc_vars, exc_lineno_cnames, exc_filename_cname) code, temps_to_clean_up, exc_vars, exc_lineno_cnames, exc_filename_cname)
finally_old_labels = code.all_new_labels() finally_old_labels = code.all_new_labels()
...@@ -6539,14 +6538,25 @@ class TryFinallyStatNode(StatNode): ...@@ -6539,14 +6538,25 @@ class TryFinallyStatNode(StatNode):
def put_error_catcher(self, code, temps_to_clean_up, exc_vars, def put_error_catcher(self, code, temps_to_clean_up, exc_vars,
exc_lineno_cnames, exc_filename_cname): exc_lineno_cnames, exc_filename_cname):
code.globalstate.use_utility_code(restore_exception_utility_code) code.globalstate.use_utility_code(restore_exception_utility_code)
code.globalstate.use_utility_code(get_exception_utility_code)
code.globalstate.use_utility_code(swap_exception_utility_code)
code.putln(' '.join(["%s = 0;"]*len(exc_vars)) % exc_vars)
if self.is_try_finally_in_nogil: if self.is_try_finally_in_nogil:
code.put_ensure_gil(declare_gilstate=False) code.put_ensure_gil(declare_gilstate=False)
for temp_name, type in temps_to_clean_up: for temp_name, type in temps_to_clean_up:
code.put_xdecref_clear(temp_name, type) code.put_xdecref_clear(temp_name, type)
code.putln("__Pyx_ErrFetch(&%s, &%s, &%s);" % exc_vars) # not using preprocessor here to avoid warnings about
# unused utility functions and/or temps
code.putln("if (PY_MAJOR_VERSION >= 3)"
" __Pyx_ExceptionSwap(&%s, &%s, &%s);" % exc_vars[3:])
code.putln("if ((PY_MAJOR_VERSION < 3) ||"
# if __Pyx_GetException() fails in Py3,
# store the newly raised exception instead
" unlikely(__Pyx_GetException(&%s, &%s, &%s) < 0)) "
"__Pyx_ErrFetch(&%s, &%s, &%s);" % (exc_vars[:3] * 2))
for var in exc_vars: for var in exc_vars:
code.put_xgotref(var) code.put_xgotref(var)
if exc_lineno_cnames: if exc_lineno_cnames:
...@@ -6560,18 +6570,24 @@ class TryFinallyStatNode(StatNode): ...@@ -6560,18 +6570,24 @@ class TryFinallyStatNode(StatNode):
def put_error_uncatcher(self, code, exc_vars, exc_lineno_cnames, exc_filename_cname): def put_error_uncatcher(self, code, exc_vars, exc_lineno_cnames, exc_filename_cname):
code.globalstate.use_utility_code(restore_exception_utility_code) code.globalstate.use_utility_code(restore_exception_utility_code)
code.globalstate.use_utility_code(reset_exception_utility_code)
if self.is_try_finally_in_nogil: if self.is_try_finally_in_nogil:
code.put_ensure_gil(declare_gilstate=False) code.put_ensure_gil(declare_gilstate=False)
for var in exc_vars: code.putln("#if PY_MAJOR_VERSION >= 3")
for var in exc_vars[3:]:
code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s, %s, %s);" % exc_vars[3:])
code.putln("#endif")
for var in exc_vars[:3]:
code.put_xgiveref(var) code.put_xgiveref(var)
code.putln("__Pyx_ErrRestore(%s, %s, %s);" % exc_vars) code.putln("__Pyx_ErrRestore(%s, %s, %s);" % exc_vars[:3])
if self.is_try_finally_in_nogil: if self.is_try_finally_in_nogil:
code.put_release_ensured_gil() code.put_release_ensured_gil()
code.putln("%s = 0; %s = 0; %s = 0;" % exc_vars) code.putln(' '.join(["%s = 0;"]*len(exc_vars)) % exc_vars)
if exc_lineno_cnames: if exc_lineno_cnames:
code.putln("%s = %s; %s = %s; %s = %s;" % ( code.putln("%s = %s; %s = %s; %s = %s;" % (
Naming.lineno_cname, exc_lineno_cnames[0], Naming.lineno_cname, exc_lineno_cnames[0],
...@@ -6579,12 +6595,19 @@ class TryFinallyStatNode(StatNode): ...@@ -6579,12 +6595,19 @@ class TryFinallyStatNode(StatNode):
Naming.filename_cname, exc_filename_cname)) Naming.filename_cname, exc_filename_cname))
def put_error_cleaner(self, code, exc_vars): def put_error_cleaner(self, code, exc_vars):
code.globalstate.use_utility_code(reset_exception_utility_code)
if self.is_try_finally_in_nogil: if self.is_try_finally_in_nogil:
code.put_ensure_gil(declare_gilstate=False) code.put_ensure_gil(declare_gilstate=False)
for var in exc_vars: code.putln("#if PY_MAJOR_VERSION >= 3")
for var in exc_vars[3:]:
code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s, %s, %s);" % exc_vars[3:])
code.putln("#endif")
for var in exc_vars[:3]:
code.put_xdecref_clear(var, py_object_type) code.put_xdecref_clear(var, py_object_type)
if self.is_try_finally_in_nogil: if self.is_try_finally_in_nogil:
code.put_release_ensured_gil() code.put_release_ensured_gil()
code.putln(' '.join(["%s = 0;"]*3) % exc_vars[3:])
def annotate(self, code): def annotate(self, code):
self.body.annotate(code) self.body.annotate(code)
......
...@@ -272,12 +272,14 @@ static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) ...@@ -272,12 +272,14 @@ static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb)
#endif #endif
goto bad; goto bad;
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0)) if (local_tb) {
goto bad; if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0))
goto bad;
}
#endif #endif
Py_XINCREF(local_tb);
Py_INCREF(local_type); Py_INCREF(local_type);
Py_INCREF(local_value); Py_INCREF(local_value);
Py_INCREF(local_tb);
*type = local_type; *type = local_type;
*value = local_value; *value = local_value;
*tb = local_tb; *tb = local_tb;
......
...@@ -42,11 +42,35 @@ def finally_pass(): ...@@ -42,11 +42,35 @@ def finally_pass():
pass pass
cdef void swallow(): def except_finally_reraise():
"""
>>> def py_check():
... try: raise ValueError
... except ValueError:
... for i in range(2):
... try: raise TypeError
... finally:
... break
... assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
... raise
...
>>> py_check()
Traceback (most recent call last):
ValueError
>>> except_finally_reraise()
Traceback (most recent call last):
ValueError
"""
try: try:
raise TypeError() raise ValueError
finally: except ValueError:
return for i in range(2):
try:
raise TypeError
finally:
break
assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
raise
def finally_exception_check_return(): def finally_exception_check_return():
...@@ -70,23 +94,33 @@ def finally_exception_check_return(): ...@@ -70,23 +94,33 @@ def finally_exception_check_return():
raise ValueError() raise ValueError()
finally: finally:
if IS_PY3: if IS_PY3:
pass # FIXME: assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
#assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
else: else:
assert sys.exc_info() == (None, None, None), str(sys.exc_info()) assert sys.exc_info() == (None, None, None), str(sys.exc_info())
return 1 return 1
cdef void swallow():
try:
raise TypeError()
except:
return
def finally_exception_check_swallow(): def finally_exception_check_swallow():
""" """
>>> if not IS_PY3: >>> if not IS_PY3:
... sys.exc_clear() ... sys.exc_clear()
>>> def swallow(): >>> def swallow():
... try: raise TypeError() ... try: raise TypeError()
... finally: return ... except: return
>>> def py_check(): >>> def py_check():
... try: raise ValueError() ... try: raise ValueError()
... finally: ... finally:
... if IS_PY3:
... assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
... else:
... assert sys.exc_info() == (None, None, None), str(sys.exc_info())
... swallow() ... swallow()
... if IS_PY3: ... if IS_PY3:
... assert sys.exc_info()[0] == ValueError, str(sys.exc_info()) ... assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
...@@ -104,10 +138,13 @@ def finally_exception_check_swallow(): ...@@ -104,10 +138,13 @@ def finally_exception_check_swallow():
try: try:
raise ValueError() raise ValueError()
finally: finally:
if IS_PY3:
assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
else:
assert sys.exc_info() == (None, None, None), str(sys.exc_info())
swallow() swallow()
if IS_PY3: if IS_PY3:
pass # FIXME: assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
#assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
else: else:
assert sys.exc_info() == (None, None, None), str(sys.exc_info()) assert sys.exc_info() == (None, None, None), str(sys.exc_info())
...@@ -139,8 +176,7 @@ def finally_exception_break_check(): ...@@ -139,8 +176,7 @@ def finally_exception_break_check():
raise ValueError() raise ValueError()
finally: finally:
if IS_PY3: if IS_PY3:
pass # FIXME: assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
#assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
else: else:
assert sys.exc_info() == (None, None, None), str(sys.exc_info()) assert sys.exc_info() == (None, None, None), str(sys.exc_info())
break break
...@@ -154,12 +190,16 @@ def finally_exception_break_check_with_swallowed_raise(): ...@@ -154,12 +190,16 @@ def finally_exception_break_check_with_swallowed_raise():
... sys.exc_clear() ... sys.exc_clear()
>>> def swallow(): >>> def swallow():
... try: raise TypeError() ... try: raise TypeError()
... finally: return ... except: return
>>> def py_check(): >>> def py_check():
... i = None ... i = None
... for i in range(2): ... for i in range(2):
... try: raise ValueError() ... try: raise ValueError()
... finally: ... finally:
... if IS_PY3:
... assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
... else:
... assert sys.exc_info() == (None, None, None), str(sys.exc_info())
... swallow() ... swallow()
... if IS_PY3: ... if IS_PY3:
... assert sys.exc_info()[0] == ValueError, str(sys.exc_info()) ... assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
...@@ -178,10 +218,13 @@ def finally_exception_break_check_with_swallowed_raise(): ...@@ -178,10 +218,13 @@ def finally_exception_break_check_with_swallowed_raise():
try: try:
raise ValueError() raise ValueError()
finally: finally:
if IS_PY3:
assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
else:
assert sys.exc_info() == (None, None, None), str(sys.exc_info())
swallow() swallow()
if IS_PY3: if IS_PY3:
pass # FIXME: assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
#assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
else: else:
assert sys.exc_info() == (None, None, None), str(sys.exc_info()) assert sys.exc_info() == (None, None, None), str(sys.exc_info())
break break
......
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