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):
exc_lineno_cnames = exc_filename_cname = None
exc_vars = tuple([
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.putln("%s = 0; %s = 0; %s = 0;" % exc_vars)
self.put_error_catcher(
code, temps_to_clean_up, exc_vars, exc_lineno_cnames, exc_filename_cname)
finally_old_labels = code.all_new_labels()
......@@ -6539,14 +6538,25 @@ class TryFinallyStatNode(StatNode):
def put_error_catcher(self, code, temps_to_clean_up, exc_vars,
exc_lineno_cnames, exc_filename_cname):
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:
code.put_ensure_gil(declare_gilstate=False)
for temp_name, type in temps_to_clean_up:
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:
code.put_xgotref(var)
if exc_lineno_cnames:
......@@ -6560,18 +6570,24 @@ class TryFinallyStatNode(StatNode):
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(reset_exception_utility_code)
if self.is_try_finally_in_nogil:
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.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:
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:
code.putln("%s = %s; %s = %s; %s = %s;" % (
Naming.lineno_cname, exc_lineno_cnames[0],
......@@ -6579,12 +6595,19 @@ class TryFinallyStatNode(StatNode):
Naming.filename_cname, exc_filename_cname))
def put_error_cleaner(self, code, exc_vars):
code.globalstate.use_utility_code(reset_exception_utility_code)
if self.is_try_finally_in_nogil:
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)
if self.is_try_finally_in_nogil:
code.put_release_ensured_gil()
code.putln(' '.join(["%s = 0;"]*3) % exc_vars[3:])
def annotate(self, code):
self.body.annotate(code)
......
......@@ -272,12 +272,14 @@ static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb)
#endif
goto bad;
#if PY_MAJOR_VERSION >= 3
if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0))
goto bad;
if (local_tb) {
if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0))
goto bad;
}
#endif
Py_XINCREF(local_tb);
Py_INCREF(local_type);
Py_INCREF(local_value);
Py_INCREF(local_tb);
*type = local_type;
*value = local_value;
*tb = local_tb;
......
......@@ -42,11 +42,35 @@ def finally_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:
raise TypeError()
finally:
return
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
def finally_exception_check_return():
......@@ -70,23 +94,33 @@ def finally_exception_check_return():
raise ValueError()
finally:
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:
assert sys.exc_info() == (None, None, None), str(sys.exc_info())
return 1
cdef void swallow():
try:
raise TypeError()
except:
return
def finally_exception_check_swallow():
"""
>>> if not IS_PY3:
... sys.exc_clear()
>>> def swallow():
... try: raise TypeError()
... finally: return
... except: return
>>> def py_check():
... try: raise ValueError()
... 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()
... if IS_PY3:
... assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
......@@ -104,10 +138,13 @@ def finally_exception_check_swallow():
try:
raise ValueError()
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()
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:
assert sys.exc_info() == (None, None, None), str(sys.exc_info())
......@@ -139,8 +176,7 @@ def finally_exception_break_check():
raise ValueError()
finally:
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:
assert sys.exc_info() == (None, None, None), str(sys.exc_info())
break
......@@ -154,12 +190,16 @@ def finally_exception_break_check_with_swallowed_raise():
... sys.exc_clear()
>>> def swallow():
... try: raise TypeError()
... finally: return
... except: return
>>> def py_check():
... i = None
... for i in range(2):
... try: raise ValueError()
... 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()
... if IS_PY3:
... assert sys.exc_info()[0] == ValueError, str(sys.exc_info())
......@@ -178,10 +218,13 @@ def finally_exception_break_check_with_swallowed_raise():
try:
raise ValueError()
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()
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:
assert sys.exc_info() == (None, None, None), str(sys.exc_info())
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