py: Handle case of return within the finally block of try-finally.
Addresses issue #1636.
This commit is contained in:
parent
117158fcd5
commit
8047340d75
8
py/vm.c
8
py/vm.c
|
@ -1032,6 +1032,14 @@ unwind_jump:;
|
||||||
|
|
||||||
ENTRY(MP_BC_RETURN_VALUE):
|
ENTRY(MP_BC_RETURN_VALUE):
|
||||||
MARK_EXC_IP_SELECTIVE();
|
MARK_EXC_IP_SELECTIVE();
|
||||||
|
// These next 3 lines pop a try-finally exception handler, if one
|
||||||
|
// is there on the exception stack. Without this the finally block
|
||||||
|
// is executed a second time when the return is executed, because
|
||||||
|
// the try-finally exception handler is still on the stack.
|
||||||
|
// TODO Possibly find a better way to handle this case.
|
||||||
|
if (currently_in_except_block) {
|
||||||
|
POP_EXC_BLOCK();
|
||||||
|
}
|
||||||
unwind_return:
|
unwind_return:
|
||||||
while (exc_sp >= exc_stack) {
|
while (exc_sp >= exc_stack) {
|
||||||
if (MP_TAGPTR_TAG1(exc_sp->val_sp)) {
|
if (MP_TAGPTR_TAG1(exc_sp->val_sp)) {
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
# test 'return' within the finally block
|
||||||
|
# it should swallow the exception
|
||||||
|
|
||||||
|
# simple case
|
||||||
|
def f():
|
||||||
|
try:
|
||||||
|
raise ValueError()
|
||||||
|
finally:
|
||||||
|
print('finally')
|
||||||
|
return 0
|
||||||
|
print('got here')
|
||||||
|
print(f())
|
||||||
|
|
||||||
|
# nested, return in outer
|
||||||
|
def f():
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
raise ValueError
|
||||||
|
finally:
|
||||||
|
print('finally 1')
|
||||||
|
print('got here')
|
||||||
|
finally:
|
||||||
|
print('finally 2')
|
||||||
|
return 2
|
||||||
|
print('got here')
|
||||||
|
print(f())
|
||||||
|
|
||||||
|
# nested, return in inner
|
||||||
|
def f():
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
raise ValueError
|
||||||
|
finally:
|
||||||
|
print('finally 1')
|
||||||
|
return 1
|
||||||
|
print('got here')
|
||||||
|
finally:
|
||||||
|
print('finally 2')
|
||||||
|
print('got here')
|
||||||
|
print(f())
|
||||||
|
|
||||||
|
# nested, return in inner and outer
|
||||||
|
def f():
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
raise ValueError
|
||||||
|
finally:
|
||||||
|
print('finally 1')
|
||||||
|
return 1
|
||||||
|
print('got here')
|
||||||
|
finally:
|
||||||
|
print('finally 2')
|
||||||
|
return 2
|
||||||
|
print('got here')
|
||||||
|
print(f())
|
||||||
|
|
||||||
|
# nested with reraise
|
||||||
|
def f():
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
raise ValueError
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
print('got here')
|
||||||
|
finally:
|
||||||
|
print('finally')
|
||||||
|
return 0
|
||||||
|
print('got here')
|
||||||
|
print(f())
|
||||||
|
|
||||||
|
# triple nesting with reraise
|
||||||
|
def f():
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
raise ValueError
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
print('finally')
|
||||||
|
return 0
|
||||||
|
print(f())
|
||||||
|
|
||||||
|
# exception when matching exception
|
||||||
|
def f():
|
||||||
|
try:
|
||||||
|
raise ValueError
|
||||||
|
except NonExistingError:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
print('finally')
|
||||||
|
return 0
|
||||||
|
print(f())
|
||||||
|
|
||||||
|
# raising exception class, not instance
|
||||||
|
def f():
|
||||||
|
try:
|
||||||
|
raise ValueError
|
||||||
|
finally:
|
||||||
|
print('finally')
|
||||||
|
return 0
|
||||||
|
print(f())
|
Loading…
Reference in New Issue